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