1 |
/************************************************************************************************* |
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 */ |