1 |
dpavlin |
2 |
/************************************************************************************************* |
2 |
|
|
* Implementation of the MT-safe API |
3 |
|
|
* Copyright (C) 2004-2005 Mikio Hirabayashi |
4 |
|
|
* This file is part of Hyper Estraier. |
5 |
|
|
* Hyper Estraier is free software; you can redistribute it and/or modify it under the terms of |
6 |
|
|
* the GNU Lesser General Public License as published by the Free Software Foundation; either |
7 |
|
|
* version 2.1 of the License or any later version. Hyper Estraier is distributed in the hope |
8 |
|
|
* that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of |
9 |
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public |
10 |
|
|
* License for more details. |
11 |
|
|
* You should have received a copy of the GNU Lesser General Public License along with Hyper |
12 |
|
|
* Estraier; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, |
13 |
|
|
* Boston, MA 02111-1307 USA. |
14 |
|
|
*************************************************************************************************/ |
15 |
|
|
|
16 |
|
|
|
17 |
|
|
#include "estraier.h" |
18 |
|
|
#include "estmtdb.h" |
19 |
|
|
#include "myconf.h" |
20 |
|
|
|
21 |
|
|
#define ESTMINIBNUM 31 /* bucket number of map for attributes */ |
22 |
|
|
|
23 |
|
|
|
24 |
|
|
/* private function prototypes */ |
25 |
|
|
static int est_global_lock(void); |
26 |
|
|
static void est_global_unlock(void); |
27 |
|
|
static int est_mtdb_lock(ESTMTDB *db); |
28 |
|
|
static void est_mtdb_unlock(ESTMTDB *db); |
29 |
|
|
|
30 |
|
|
|
31 |
|
|
|
32 |
|
|
/************************************************************************************************* |
33 |
|
|
* API for MT-safe database |
34 |
|
|
*************************************************************************************************/ |
35 |
|
|
|
36 |
|
|
|
37 |
|
|
/* Global mutex. */ |
38 |
|
|
pthread_mutex_t est_global_mutex = PTHREAD_MUTEX_INITIALIZER; |
39 |
|
|
CBMAP *est_global_db_names = NULL; |
40 |
|
|
|
41 |
|
|
|
42 |
|
|
/* Open a database. */ |
43 |
|
|
ESTMTDB *est_mtdb_open(const char *name, int omode, int *ecp){ |
44 |
|
|
ESTMTDB *mtdb; |
45 |
|
|
ESTDB *db; |
46 |
|
|
char *path; |
47 |
|
|
assert(name && ecp); |
48 |
|
|
if(!est_global_lock()){ |
49 |
|
|
*ecp = ESTELOCK; |
50 |
|
|
return NULL; |
51 |
|
|
} |
52 |
|
|
if(!est_global_db_names){ |
53 |
|
|
est_global_db_names = cbmapopenex(ESTMINIBNUM); |
54 |
|
|
cbglobalgc(est_global_db_names, (void (*)(void *))cbmapclose); |
55 |
|
|
} |
56 |
|
|
path = est_realpath(name); |
57 |
|
|
if(cbmapget(est_global_db_names, path, -1, NULL)){ |
58 |
|
|
free(path); |
59 |
|
|
*ecp = ESTEACCES; |
60 |
|
|
est_global_unlock(); |
61 |
|
|
return NULL; |
62 |
|
|
} |
63 |
|
|
mtdb = cbmalloc(sizeof(ESTMTDB)); |
64 |
|
|
if(!(db = est_db_open(name, omode, ecp))){ |
65 |
|
|
free(path); |
66 |
|
|
est_global_unlock(); |
67 |
|
|
return NULL; |
68 |
|
|
} |
69 |
|
|
free(path); |
70 |
|
|
path = est_realpath(name); |
71 |
|
|
cbmapput(est_global_db_names, path, -1, "", 0, FALSE); |
72 |
|
|
mtdb->db = db; |
73 |
|
|
mtdb->path = path; |
74 |
|
|
pthread_mutex_init(&(mtdb->mutex), NULL); |
75 |
|
|
est_global_unlock(); |
76 |
|
|
return mtdb; |
77 |
|
|
} |
78 |
|
|
|
79 |
|
|
|
80 |
|
|
/* Close a database. */ |
81 |
|
|
int est_mtdb_close(ESTMTDB *db, int *ecp){ |
82 |
|
|
int err; |
83 |
|
|
assert(db && ecp); |
84 |
|
|
if(!est_global_lock()){ |
85 |
|
|
*ecp = ESTELOCK; |
86 |
|
|
return FALSE; |
87 |
|
|
} |
88 |
|
|
err = FALSE; |
89 |
|
|
cbmapout(est_global_db_names, db->path, -1); |
90 |
|
|
pthread_mutex_destroy(&(db->mutex)); |
91 |
|
|
free(db->path); |
92 |
|
|
if(!est_db_close(db->db, ecp)) err = TRUE; |
93 |
|
|
free(db); |
94 |
|
|
est_global_unlock(); |
95 |
|
|
return err ? FALSE : TRUE; |
96 |
|
|
} |
97 |
|
|
|
98 |
|
|
|
99 |
|
|
/* Get the last happended error code of a database. */ |
100 |
|
|
int est_mtdb_error(ESTMTDB *db){ |
101 |
|
|
int rv; |
102 |
|
|
assert(db); |
103 |
|
|
if(!est_mtdb_lock(db)) return ESTELOCK; |
104 |
|
|
rv = est_db_error(db->db); |
105 |
|
|
est_mtdb_unlock(db); |
106 |
|
|
return rv; |
107 |
|
|
} |
108 |
|
|
|
109 |
|
|
|
110 |
|
|
/* Check whether a database has a fatal error. */ |
111 |
|
|
int est_mtdb_fatal(ESTMTDB *db){ |
112 |
|
|
int rv; |
113 |
|
|
assert(db); |
114 |
|
|
if(!est_mtdb_lock(db)) return FALSE; |
115 |
|
|
rv = est_db_fatal(db->db); |
116 |
|
|
est_mtdb_unlock(db); |
117 |
|
|
return rv; |
118 |
|
|
} |
119 |
|
|
|
120 |
|
|
|
121 |
|
|
/* Flush index words in the cache of a database. */ |
122 |
|
|
int est_mtdb_flush(ESTMTDB *db, int max){ |
123 |
|
|
int rv; |
124 |
|
|
assert(db); |
125 |
|
|
if(!est_mtdb_lock(db)) return FALSE; |
126 |
|
|
rv = est_db_flush(db->db, max); |
127 |
|
|
est_mtdb_unlock(db); |
128 |
|
|
return rv; |
129 |
|
|
} |
130 |
|
|
|
131 |
|
|
|
132 |
|
|
/* Synchronize updating contents of a database. */ |
133 |
|
|
int est_mtdb_sync(ESTMTDB *db){ |
134 |
|
|
int rv; |
135 |
|
|
assert(db); |
136 |
|
|
if(!est_mtdb_lock(db)) return FALSE; |
137 |
|
|
rv = est_db_sync(db->db); |
138 |
|
|
est_mtdb_unlock(db); |
139 |
|
|
return rv; |
140 |
|
|
} |
141 |
|
|
|
142 |
|
|
|
143 |
|
|
/* Optimize a database. */ |
144 |
|
|
int est_mtdb_optimize(ESTMTDB *db, int options){ |
145 |
|
|
int rv; |
146 |
|
|
assert(db); |
147 |
|
|
if(!est_mtdb_lock(db)) return FALSE; |
148 |
|
|
rv = est_db_optimize(db->db, options); |
149 |
|
|
est_mtdb_unlock(db); |
150 |
|
|
return rv; |
151 |
|
|
} |
152 |
|
|
|
153 |
|
|
|
154 |
|
|
/* Add a document to a database. */ |
155 |
|
|
int est_mtdb_put_doc(ESTMTDB *db, ESTDOC *doc, int options){ |
156 |
|
|
int rv; |
157 |
|
|
assert(db && doc); |
158 |
|
|
if(!est_mtdb_lock(db)) return FALSE; |
159 |
|
|
rv = est_db_put_doc(db->db, doc, options); |
160 |
|
|
est_mtdb_unlock(db); |
161 |
|
|
return rv; |
162 |
|
|
} |
163 |
|
|
|
164 |
|
|
|
165 |
|
|
/* Remove a document from a database. */ |
166 |
|
|
int est_mtdb_out_doc(ESTMTDB *db, int id, int options){ |
167 |
|
|
int rv; |
168 |
|
|
assert(db && id > 0); |
169 |
|
|
if(!est_mtdb_lock(db)) return FALSE; |
170 |
|
|
rv = est_db_out_doc(db->db, id, options); |
171 |
|
|
est_mtdb_unlock(db); |
172 |
|
|
return rv; |
173 |
|
|
} |
174 |
|
|
|
175 |
|
|
|
176 |
|
|
/* Retrieve a document in a database. */ |
177 |
|
|
ESTDOC *est_mtdb_get_doc(ESTMTDB *db, int id, int options){ |
178 |
|
|
ESTDOC *rv; |
179 |
|
|
assert(db && id > 0); |
180 |
|
|
if(!est_mtdb_lock(db)) return NULL; |
181 |
|
|
rv = est_db_get_doc(db->db, id, options); |
182 |
|
|
est_mtdb_unlock(db); |
183 |
|
|
return rv; |
184 |
|
|
} |
185 |
|
|
|
186 |
|
|
|
187 |
|
|
/* Retrieve the value of an attribute of a document in a database. */ |
188 |
|
|
char *est_mtdb_get_doc_attr(ESTMTDB *db, int id, const char *name){ |
189 |
|
|
char *rv; |
190 |
|
|
assert(db && id > 0 && name); |
191 |
|
|
if(!est_mtdb_lock(db)) return NULL; |
192 |
|
|
rv = est_db_get_doc_attr(db->db, id, name); |
193 |
|
|
est_mtdb_unlock(db); |
194 |
|
|
return rv; |
195 |
|
|
} |
196 |
|
|
|
197 |
|
|
|
198 |
|
|
/* Get the ID of a document spacified by URI. */ |
199 |
|
|
int est_mtdb_uri_to_id(ESTMTDB *db, const char *uri){ |
200 |
|
|
int rv; |
201 |
|
|
assert(db && uri); |
202 |
|
|
if(!est_mtdb_lock(db)) return -1; |
203 |
|
|
rv = est_db_uri_to_id(db->db, uri); |
204 |
|
|
est_mtdb_unlock(db); |
205 |
|
|
return rv; |
206 |
|
|
} |
207 |
|
|
|
208 |
|
|
|
209 |
|
|
/* Extract keywords of a document object. */ |
210 |
|
|
CBMAP *est_mtdb_etch_doc(ESTMTDB *db, ESTDOC *doc, int max){ |
211 |
|
|
CBMAP *rv; |
212 |
|
|
assert(doc && max >= 0); |
213 |
|
|
if(!est_mtdb_lock(db)) return cbmapopenex(1); |
214 |
|
|
rv = est_db_etch_doc(db->db, doc, max); |
215 |
|
|
est_mtdb_unlock(db); |
216 |
|
|
return rv; |
217 |
|
|
} |
218 |
|
|
|
219 |
|
|
|
220 |
|
|
/* Initialize the iterator of a database. */ |
221 |
|
|
int est_mtdb_iter_init(ESTMTDB *db){ |
222 |
|
|
int rv; |
223 |
|
|
assert(db); |
224 |
|
|
if(!est_mtdb_lock(db)) return FALSE; |
225 |
|
|
rv = est_db_iter_init(db->db); |
226 |
|
|
est_mtdb_unlock(db); |
227 |
|
|
return rv; |
228 |
|
|
} |
229 |
|
|
|
230 |
|
|
|
231 |
|
|
/* Get the next ID of the iterator of a database. */ |
232 |
|
|
int est_mtdb_iter_next(ESTMTDB *db){ |
233 |
|
|
int rv; |
234 |
|
|
assert(db); |
235 |
|
|
if(!est_mtdb_lock(db)) return -1; |
236 |
|
|
rv = est_db_iter_next(db->db); |
237 |
|
|
est_mtdb_unlock(db); |
238 |
|
|
return rv; |
239 |
|
|
} |
240 |
|
|
|
241 |
|
|
|
242 |
|
|
/* Get the name of a database. */ |
243 |
|
|
const char *est_mtdb_name(ESTMTDB *db){ |
244 |
|
|
const char *rv; |
245 |
|
|
assert(db); |
246 |
|
|
if(!est_mtdb_lock(db)) return ""; |
247 |
|
|
rv = est_db_name(db->db); |
248 |
|
|
est_mtdb_unlock(db); |
249 |
|
|
return rv; |
250 |
|
|
} |
251 |
|
|
|
252 |
|
|
|
253 |
|
|
/* Get the number of documents in a database. */ |
254 |
|
|
int est_mtdb_doc_num(ESTMTDB *db){ |
255 |
|
|
int rv; |
256 |
|
|
assert(db); |
257 |
|
|
if(!est_mtdb_lock(db)) return 0; |
258 |
|
|
rv = est_db_doc_num(db->db); |
259 |
|
|
est_mtdb_unlock(db); |
260 |
|
|
return rv; |
261 |
|
|
} |
262 |
|
|
|
263 |
|
|
|
264 |
|
|
/* Get the number of unique words in a database. */ |
265 |
|
|
int est_mtdb_word_num(ESTMTDB *db){ |
266 |
|
|
int rv; |
267 |
|
|
assert(db); |
268 |
|
|
if(!est_mtdb_lock(db)) return 0; |
269 |
|
|
rv = est_db_word_num(db->db); |
270 |
|
|
est_mtdb_unlock(db); |
271 |
|
|
return rv; |
272 |
|
|
} |
273 |
|
|
|
274 |
|
|
|
275 |
|
|
/* Get the size of a database. */ |
276 |
|
|
double est_mtdb_size(ESTMTDB *db){ |
277 |
|
|
double rv; |
278 |
|
|
assert(db); |
279 |
|
|
if(!est_mtdb_lock(db)) return 0.0; |
280 |
|
|
rv = est_db_size(db->db); |
281 |
|
|
est_mtdb_unlock(db); |
282 |
|
|
return rv; |
283 |
|
|
} |
284 |
|
|
|
285 |
|
|
|
286 |
|
|
/* Search documents corresponding a condition for a database. */ |
287 |
|
|
int *est_mtdb_search(ESTMTDB *db, ESTCOND *cond, int *nump, CBMAP *hints){ |
288 |
|
|
int *rv; |
289 |
|
|
assert(db && cond && nump); |
290 |
|
|
if(!est_mtdb_lock(db)){ |
291 |
|
|
est_db_set_ecode(db->db, ESTELOCK); |
292 |
|
|
cbmapput(hints, "", 0, "0", -1, TRUE); |
293 |
|
|
*nump = 0; |
294 |
|
|
return cbmalloc(1); |
295 |
|
|
} |
296 |
|
|
rv = est_db_search(db->db, cond, nump, hints); |
297 |
|
|
est_mtdb_unlock(db); |
298 |
|
|
return rv; |
299 |
|
|
} |
300 |
|
|
|
301 |
|
|
|
302 |
|
|
/* Set the maximum size of the cache memory of a database. */ |
303 |
|
|
void est_mtdb_set_cache_size(ESTMTDB *db, size_t size, int anum, int tnum){ |
304 |
|
|
assert(db); |
305 |
|
|
if(!est_mtdb_lock(db)) return; |
306 |
|
|
est_db_set_cache_size(db->db, size, anum, tnum); |
307 |
|
|
est_mtdb_unlock(db); |
308 |
|
|
} |
309 |
|
|
|
310 |
|
|
|
311 |
|
|
/* Set the special cache for narrowing and sorting with document attributes. */ |
312 |
|
|
void est_mtdb_set_special_cache(ESTMTDB *db, const char *name, int num){ |
313 |
|
|
assert(db && name && num >= 0); |
314 |
|
|
if(!est_mtdb_lock(db)) return; |
315 |
|
|
est_db_set_special_cache(db->db, name, num); |
316 |
|
|
est_mtdb_unlock(db); |
317 |
|
|
} |
318 |
|
|
|
319 |
|
|
|
320 |
|
|
|
321 |
|
|
/************************************************************************************************* |
322 |
|
|
* features for experts |
323 |
|
|
*************************************************************************************************/ |
324 |
|
|
|
325 |
|
|
|
326 |
|
|
/* Edit attributes of a document object in a database. */ |
327 |
|
|
int est_mtdb_edit_doc(ESTMTDB *db, ESTDOC *doc){ |
328 |
|
|
int rv; |
329 |
|
|
assert(db && doc); |
330 |
|
|
if(!est_mtdb_lock(db)) return FALSE; |
331 |
|
|
rv = est_db_edit_doc(db->db, doc); |
332 |
|
|
est_mtdb_unlock(db); |
333 |
|
|
return rv; |
334 |
|
|
} |
335 |
|
|
|
336 |
|
|
|
337 |
|
|
/* Add a piece of meta data to a database. */ |
338 |
|
|
void est_mtdb_add_meta(ESTMTDB *db, const char *name, const char *value){ |
339 |
|
|
assert(db && name); |
340 |
|
|
if(!est_mtdb_lock(db)) return; |
341 |
|
|
est_db_add_meta(db->db, name, value); |
342 |
|
|
est_mtdb_unlock(db); |
343 |
|
|
} |
344 |
|
|
|
345 |
|
|
|
346 |
|
|
/* Get a list of names of meta data of a database. */ |
347 |
|
|
CBLIST *est_mtdb_meta_names(ESTMTDB *db){ |
348 |
|
|
CBLIST *rv; |
349 |
|
|
assert(db); |
350 |
|
|
if(!est_mtdb_lock(db)) return NULL; |
351 |
|
|
rv = est_db_meta_names(db->db); |
352 |
|
|
est_mtdb_unlock(db); |
353 |
|
|
return rv; |
354 |
|
|
} |
355 |
|
|
|
356 |
|
|
|
357 |
|
|
/* Get the value of a piece of meta data of a database. */ |
358 |
|
|
char *est_mtdb_meta(ESTMTDB *db, const char *name){ |
359 |
|
|
char *rv; |
360 |
|
|
assert(db && name); |
361 |
|
|
if(!est_mtdb_lock(db)) return NULL; |
362 |
|
|
rv = est_db_meta(db->db, name); |
363 |
|
|
est_mtdb_unlock(db); |
364 |
|
|
return rv; |
365 |
|
|
} |
366 |
|
|
|
367 |
|
|
|
368 |
|
|
/* Get the number of records in the cache memory of a database. */ |
369 |
|
|
int est_mtdb_cache_num(ESTMTDB *db){ |
370 |
|
|
int rv; |
371 |
|
|
assert(db); |
372 |
|
|
if(!est_mtdb_lock(db)) return FALSE; |
373 |
|
|
rv = est_db_cache_num(db->db); |
374 |
|
|
est_mtdb_unlock(db); |
375 |
|
|
return rv; |
376 |
|
|
} |
377 |
|
|
|
378 |
|
|
|
379 |
|
|
/* Set the callback function to inform of database events. */ |
380 |
|
|
void est_mtdb_set_informer(ESTMTDB *db, void (*func)(const char *)){ |
381 |
|
|
assert(db && func); |
382 |
|
|
if(!est_mtdb_lock(db)) return; |
383 |
|
|
est_db_set_informer(db->db, func); |
384 |
|
|
est_mtdb_unlock(db); |
385 |
|
|
} |
386 |
|
|
|
387 |
|
|
|
388 |
|
|
/* Set the callback function to create a vector of keywords of a document. */ |
389 |
|
|
void est_mtdb_set_vectorizer(ESTMTDB *db, CBMAP *(*func)(void *, int, void *), void *data){ |
390 |
|
|
assert(db && func); |
391 |
|
|
if(!est_mtdb_lock(db)) return; |
392 |
|
|
est_db_set_vectorizer(db->db, func, data); |
393 |
|
|
est_mtdb_unlock(db); |
394 |
|
|
} |
395 |
|
|
|
396 |
|
|
|
397 |
|
|
/* Fill the cache for keys for TF-IDF. */ |
398 |
|
|
void est_mtdb_fill_key_cache(ESTMTDB *db){ |
399 |
|
|
assert(db); |
400 |
|
|
if(!est_mtdb_lock(db)) return; |
401 |
|
|
est_db_fill_key_cache(db->db); |
402 |
|
|
est_mtdb_unlock(db); |
403 |
|
|
} |
404 |
|
|
|
405 |
|
|
|
406 |
|
|
|
407 |
|
|
/************************************************************************************************* |
408 |
|
|
* private objects |
409 |
|
|
*************************************************************************************************/ |
410 |
|
|
|
411 |
|
|
|
412 |
|
|
/* Lock the global environment. |
413 |
|
|
The return value is true if success, else it is false. */ |
414 |
|
|
static int est_global_lock(void){ |
415 |
|
|
return pthread_mutex_lock(&est_global_mutex) == 0; |
416 |
|
|
} |
417 |
|
|
|
418 |
|
|
|
419 |
|
|
/* Unlock the global environment. */ |
420 |
|
|
static void est_global_unlock(void){ |
421 |
|
|
pthread_mutex_unlock(&est_global_mutex); |
422 |
|
|
} |
423 |
|
|
|
424 |
|
|
|
425 |
|
|
/* Lock a database object. |
426 |
|
|
`db' specifies a database object. |
427 |
|
|
The return value is true if success, else it is false. */ |
428 |
|
|
static int est_mtdb_lock(ESTMTDB *db){ |
429 |
|
|
assert(db); |
430 |
|
|
if(dpisreentrant){ |
431 |
|
|
if(pthread_mutex_lock(&(db->mutex)) != 0){ |
432 |
|
|
est_db_set_ecode(db->db, ESTELOCK); |
433 |
|
|
return FALSE; |
434 |
|
|
} |
435 |
|
|
return TRUE; |
436 |
|
|
} |
437 |
|
|
if(pthread_mutex_lock(&est_global_mutex) != 0){ |
438 |
|
|
est_db_set_ecode(db->db, ESTELOCK); |
439 |
|
|
return FALSE; |
440 |
|
|
} |
441 |
|
|
return TRUE; |
442 |
|
|
} |
443 |
|
|
|
444 |
|
|
|
445 |
|
|
/* Unlock a database object. |
446 |
|
|
`db' specifies a database object. */ |
447 |
|
|
static void est_mtdb_unlock(ESTMTDB *db){ |
448 |
|
|
assert(db); |
449 |
|
|
if(dpisreentrant){ |
450 |
|
|
pthread_mutex_unlock(&(db->mutex)); |
451 |
|
|
} else { |
452 |
|
|
pthread_mutex_unlock(&est_global_mutex); |
453 |
|
|
} |
454 |
|
|
} |
455 |
|
|
|
456 |
|
|
|
457 |
|
|
|
458 |
|
|
/* END OF FILE */ |