1 /*===========================================================================
2 *
3 * PUBLIC DOMAIN NOTICE
4 * National Center for Biotechnology Information
5 *
6 * This software/database is a "United States Government Work" under the
7 * terms of the United States Copyright Act. It was written as part of
8 * the author's official duties as a United States Government employee and
9 * thus cannot be copyrighted. This software/database is freely available
10 * to the public for use. The National Library of Medicine and the U.S.
11 * Government have not placed any restriction on its use or reproduction.
12 *
13 * Although all reasonable efforts have been taken to ensure the accuracy
14 * and reliability of the software and data, the NLM and the U.S.
15 * Government do not and cannot warrant the performance or results that
16 * may be obtained by using this software or data. The NLM and the U.S.
17 * Government disclaim all warranties, express or implied, including
18 * warranties of performance, merchantability or fitness for any particular
19 * purpose.
20 *
21 * Please cite the author in any work or product based on this material.
22 *
23 * ===========================================================================
24 *
25 */
26
27 #define TRACK_REFERENCES 0
28
29 #include <kdb/extern.h>
30 #include "libkdb.vers.h"
31
32 #define KONST const
33 #include "dbmgr-priv.h"
34 #include "kdb-priv.h"
35 #undef KONST
36
37 #include <vfs/manager.h>
38 #include <vfs/path.h> /* VPathGetPath */
39
40 #include <kfs/directory.h>
41 #include <klib/symbol.h>
42 #include <klib/checksum.h>
43 #include <klib/rc.h>
44 #include <kproc/lock.h>
45 #include <sysalloc.h>
46
47 #include <limits.h>
48 #include <stdlib.h>
49 #include <string.h>
50 #include <assert.h>
51
52
53 /*--------------------------------------------------------------------------
54 * KDBManager
55 * handle to library
56 */
57
58
59 /* Whack
60 */
61 static
KDBManagerWhack(KDBManager * self)62 rc_t KDBManagerWhack ( KDBManager *self )
63 {
64 rc_t rc;
65
66 KRefcountWhack ( & self -> refcount, "KDBManager" );
67
68 /* everything should be closed */
69 assert ( self -> open_objs . root == NULL );
70
71 rc = KRWLockRelease ( self -> open_objs_lock );
72
73 rc = VFSManagerRelease ( self -> vfsmgr );
74
75 rc = KDirectoryRelease ( self -> wd );
76 if ( rc == 0 )
77 {
78 free ( self );
79 return 0;
80 }
81
82 KRefcountInit ( & self -> refcount, 1, "KDBManager", "whack", "kmgr" );
83 return rc;
84 }
85
86
87 /* AddRef
88 * Release
89 * all objects are reference counted
90 * NULL references are ignored
91 */
KDBManagerAddRef(const KDBManager * self)92 LIB_EXPORT rc_t CC KDBManagerAddRef ( const KDBManager *self )
93 {
94 if ( self != NULL )
95 {
96 switch ( KRefcountAdd ( & self -> refcount, "KDBManager" ) )
97 {
98 case krefLimit:
99 return RC ( rcDB, rcMgr, rcAttaching, rcRange, rcExcessive );
100 }
101 }
102 return 0;
103 }
104
KDBManagerRelease(const KDBManager * self)105 LIB_EXPORT rc_t CC KDBManagerRelease ( const KDBManager *self )
106 {
107 if ( self != NULL )
108 {
109 switch ( KRefcountDrop ( & self -> refcount, "KDBManager" ) )
110 {
111 case krefWhack:
112 return KDBManagerWhack ( ( KDBManager* ) self );
113 case krefNegative:
114 return RC ( rcDB, rcMgr, rcReleasing, rcRange, rcExcessive );
115 }
116 }
117 return 0;
118 }
119
120
121 /* Attach
122 * Sever
123 */
KDBManagerAttach(const KDBManager * self)124 KDBManager* KDBManagerAttach ( const KDBManager *self )
125 {
126 if ( self != NULL )
127 {
128 switch ( KRefcountAddDep ( & self -> refcount, "KDBManager" ) )
129 {
130 case krefLimit:
131 return NULL;
132 }
133 }
134 return ( KDBManager* ) self;
135 }
136
KDBManagerSever(const KDBManager * self)137 rc_t KDBManagerSever ( const KDBManager *self )
138 {
139 if ( self != NULL )
140 {
141 switch ( KRefcountDropDep ( & self -> refcount, "KDBManager" ) )
142 {
143 case krefWhack:
144 return KDBManagerWhack ( ( KDBManager* ) self );
145 case krefNegative:
146 return RC ( rcDB, rcMgr, rcReleasing, rcRange, rcExcessive );
147 }
148 }
149 return 0;
150 }
151
152
153 /* Make - PRIVATE
154 *
155 * "wd" [ IN, NULL OKAY ] - optional working directory for
156 * accessing the file system. mgr will attach its own reference.
157 */
KDBManagerMake(KDBManager ** mgrp,const KDirectory * wd,const char * op,VFSManager * vmanager)158 rc_t KDBManagerMake ( KDBManager **mgrp, const KDirectory *wd, const char *op,
159 VFSManager *vmanager )
160 {
161 rc_t rc;
162
163 if ( mgrp == NULL )
164 rc = RC ( rcDB, rcMgr, rcConstructing, rcParam, rcNull );
165 else
166 {
167 KDBManager *mgr = malloc ( sizeof * mgr );
168 if ( mgr == NULL )
169 rc = RC ( rcDB, rcMgr, rcConstructing, rcMemory, rcExhausted );
170 else
171 {
172 memset ( mgr, 0, sizeof * mgr );
173 mgr -> wd = wd;
174 if ( wd != NULL )
175 rc = KDirectoryAddRef ( wd );
176 else
177 rc = KDirectoryNativeDir ( ( KDirectory** ) & mgr -> wd );
178
179 if ( rc == 0 )
180 {
181 if (vmanager == NULL) {
182 rc = VFSManagerMake ( & mgr -> vfsmgr );
183 }
184 else {
185 rc = VFSManagerAddRef ( vmanager );
186 if (rc == 0) {
187 mgr -> vfsmgr = vmanager;
188 }
189 }
190
191 if ( rc == 0 )
192 {
193 rc = KRWLockMake ( & mgr -> open_objs_lock );
194
195 if ( rc == 0 )
196 {
197 CRC32Init ();
198
199 BSTreeInit ( & mgr -> open_objs );
200
201 KRefcountInit ( & mgr -> refcount, 1, "KDBManager", op, "kmgr" );
202
203 * mgrp = mgr;
204 return 0;
205 }
206
207 VFSManagerRelease ( mgr -> vfsmgr );
208 }
209
210 KDirectoryRelease ( mgr -> wd );
211 }
212
213 free ( mgr );
214 }
215
216 * mgrp = NULL;
217 }
218
219 return rc;
220 }
221
222
KDBManagerGetVFSManager(const KDBManager * self,const struct VFSManager ** vmanager)223 LIB_EXPORT rc_t CC KDBManagerGetVFSManager ( const KDBManager *self,
224 const struct VFSManager **vmanager )
225 {
226 if (self == NULL) {
227 return RC ( rcDB, rcMgr, rcAccessing, rcSelf, rcNull );
228 }
229 else if (vmanager == NULL) {
230 return RC ( rcDB, rcMgr, rcAccessing, rcParam, rcNull );
231 }
232 else {
233 rc_t rc = VFSManagerAddRef(self -> vfsmgr);
234 if (rc == 0) {
235 * vmanager = self -> vfsmgr;
236 }
237 else {
238 * vmanager = NULL;
239 }
240 return rc;
241 }
242 }
243
244
245 /* Version
246 * returns the library version
247 */
KDBManagerVersion(const KDBManager * self,uint32_t * version)248 LIB_EXPORT rc_t CC KDBManagerVersion ( const KDBManager *self, uint32_t *version )
249 {
250 if ( version == NULL )
251 return RC ( rcDB, rcMgr, rcAccessing, rcParam, rcNull );
252 if ( self == NULL )
253 return RC ( rcDB, rcMgr, rcAccessing, rcSelf, rcNull );
254
255 * version = LIBKDB_VERS;
256 return 0;
257 }
258
259
260 /* Exists
261 * returns true if requested object exists
262 *
263 * "requested" [ IN ] - a KDBPathType
264 *
265 * "path" [ IN ] - NUL terminated path
266 */
KDBManagerVExists(const KDBManager * self,uint32_t requested,const char * name,va_list args)267 LIB_EXPORT bool CC KDBManagerVExists ( const KDBManager *self, uint32_t requested, const char *name, va_list args )
268 {
269 int type;
270
271 type = KDBManagerVPathType (self, name, args);
272 switch ( type )
273 {
274 case kptDatabase:
275 case kptTable:
276 case kptIndex:
277 case kptColumn:
278 case kptMetadata:
279 break;
280 case kptPrereleaseTbl:
281 type = kptTable;
282 break;
283 default:
284 return false;
285 }
286 return requested == ( uint32_t ) type;
287 }
288
KDBManagerExists(const KDBManager * self,uint32_t type,const char * name,...)289 bool KDBManagerExists ( const KDBManager *self, uint32_t type, const char *name, ... )
290 {
291 bool exists;
292
293 va_list args;
294 va_start ( args, name );
295
296 exists = KDBManagerVExists ( self, type, name, args );
297
298 va_end ( args );
299
300 return exists;
301 }
302
303
304 /* Writable
305 * returns 0 if object is writable
306 * or a reason why if not
307 *
308 * "path" [ IN ] - NUL terminated path
309 */
310
311 /* TBD - should be in this file */
312
313 /* CheckOpen
314 */
KDBManagerCheckOpen(const KDBManager * self,const char * path)315 rc_t KDBManagerCheckOpen ( const KDBManager * self, const char *path )
316 {
317 /* try to find the open object by path */
318 KSymbol *sym = KDBManagerOpenObjectFind ( self, path );
319
320 /* if not open, return no error */
321 if ( sym == NULL )
322 return 0;
323
324 /* put together an appropriate response */
325 switch ( sym -> type )
326 {
327 case kptDatabase:
328 return RC ( rcDB, rcMgr, rcAccessing, rcDatabase, rcBusy );
329 case kptTable:
330 return RC ( rcDB, rcMgr, rcAccessing, rcTable, rcBusy );
331 case kptColumn:
332 return RC ( rcDB, rcMgr, rcAccessing, rcColumn, rcBusy );
333 case kptIndex:
334 return RC ( rcDB, rcMgr, rcAccessing, rcIndex, rcBusy );
335 case kptMetadata:
336 return RC ( rcDB, rcMgr, rcAccessing, rcMetadata, rcBusy );
337 case kptPrereleaseTbl:
338 return RC ( rcDB, rcMgr, rcAccessing, rcTable, rcBusy );
339 default:
340 break;
341 }
342
343 return RC ( rcDB, rcMgr, rcAccessing, rcUnknown, rcBusy );
344 }
345
346
347
348 /* OpenObjectFind
349 * return a pointer to the openobject with path
350 */
351 static
KDBManagerOpenObjectFindInt(const KDBManager * self,String * s)352 KSymbol *KDBManagerOpenObjectFindInt ( const KDBManager * self, String *s )
353 {
354 KSymbol *sym = NULL;
355 rc_t rc = KRWLockAcquireShared ( self -> open_objs_lock );
356 if ( rc == 0 )
357 {
358 sym = ( KSymbol* ) BSTreeFind ( & self -> open_objs, s, KSymbolCmp );
359 KRWLockUnlock ( self -> open_objs_lock );
360 }
361 return sym;
362 }
363
KDBManagerOpenObjectFind(const KDBManager * self,const char * path)364 KSymbol *KDBManagerOpenObjectFind ( const KDBManager * self, const char * path )
365 {
366 String s;
367 StringInitCString ( & s, path );
368 return KDBManagerOpenObjectFindInt ( self, & s );
369 }
370
371
372 /* OpenObjectBusy
373 * Is this path to an object in the OpenObjects list?
374 */
KDBManagerOpenObjectBusy(const KDBManager * self,const char * path)375 bool KDBManagerOpenObjectBusy ( const KDBManager *self, const char *path )
376 {
377 return KDBManagerOpenObjectFind ( self, path ) != NULL;
378 }
379
380
381 /* OpenObjectAdd
382 * Put an object in to the open objects list
383 */
KDBManagerOpenObjectAdd(KDBManager * self,KSymbol * obj)384 rc_t KDBManagerOpenObjectAdd ( KDBManager *self, KSymbol *obj )
385 {
386 KSymbol *exists;
387 rc_t rc = KRWLockAcquireExcl ( self -> open_objs_lock );
388 if ( rc == 0 )
389 {
390 rc = BSTreeInsertUnique ( & self -> open_objs,
391 & obj -> n, ( BSTNode** ) & exists, KSymbolSort );
392
393 KRWLockUnlock ( self -> open_objs_lock );
394
395 if ( rc != 0 )
396 {
397 switch ( exists -> type )
398 {
399 case kptDatabase:
400 rc = RC ( rcDB, rcMgr, rcInserting, rcDatabase, rcBusy );
401 break;
402 case kptTable:
403 case kptPrereleaseTbl:
404 rc = RC ( rcDB, rcMgr, rcInserting, rcTable, rcBusy );
405 break;
406 case kptColumn:
407 rc = RC ( rcDB, rcMgr, rcInserting, rcColumn, rcBusy );
408 break;
409 case kptIndex:
410 rc = RC ( rcDB, rcMgr, rcInserting, rcIndex, rcBusy );
411 break;
412 case kptMetadata:
413 rc = RC ( rcDB, rcMgr, rcInserting, rcMetadata, rcBusy );
414 break;
415 default:
416 rc = RC ( rcDB, rcMgr, rcInserting, rcUnknown, rcBusy );
417 }
418 }
419 }
420 return rc;
421 }
422
423
424 /* OpenDelete
425 * Take an object out of the open objects list
426 */
KDBManagerOpenObjectDelete(KDBManager * self,KSymbol * obj)427 rc_t KDBManagerOpenObjectDelete ( KDBManager *self, KSymbol *obj )
428 {
429 rc_t rc = 0;
430 if ( obj != NULL )
431 {
432 rc = KRWLockAcquireExcl ( self -> open_objs_lock );
433 if ( rc == 0 )
434 {
435 /* we can expect that the only valid reason for
436 "obj" not being unlinked is that it was not in
437 the tree. other reasons would be that "obj" was
438 corrupt, but in any event, it's not in the tree */
439 if ( ! BSTreeUnlink ( & self -> open_objs, & obj -> n ) )
440
441 /* to be truly weird, we could tell what kind of node
442 it was that we didn't find */
443 rc = RC ( rcDB, rcMgr, rcRemoving, rcNode, rcNotFound );
444
445 KRWLockUnlock ( self -> open_objs_lock );
446 }
447 }
448
449 return rc;
450 }
451
452
453 /* ModDate
454 * return a modification timestamp for table
455 */
KDBManagerVGetTableModDate(const KDBManager * self,KTime_t * mtime,const char * path,va_list args)456 LIB_EXPORT rc_t CC KDBManagerVGetTableModDate ( const KDBManager *self,
457 KTime_t *mtime, const char *path, va_list args )
458 {
459 rc_t rc;
460
461 if ( mtime == NULL )
462 rc = RC ( rcDB, rcMgr, rcAccessing, rcParam, rcNull );
463 else
464 {
465 if ( self != NULL )
466 return KDBVGetPathModDate ( self -> wd, mtime, path, args );
467
468 rc = RC ( rcDB, rcMgr, rcAccessing, rcSelf, rcNull );
469 * mtime = 0;
470 }
471
472 return rc;
473 }
474
KDBManagerGetTableModDate(const KDBManager * self,KTime_t * mtime,const char * path,...)475 LIB_EXPORT rc_t CC KDBManagerGetTableModDate ( const KDBManager *self,
476 KTime_t *mtime, const char *path, ... )
477 {
478 rc_t rc;
479
480 va_list args;
481 va_start ( args, path );
482 rc = KDBManagerVGetTableModDate ( self, mtime, path, args );
483 va_end ( args );
484
485 return rc;
486 }
487