Main Page | Data Structures | Directories | File List | Data Fields | Globals

Sadie_Index.c

Go to the documentation of this file.
00001 
00025 /* This file is part of tclSadie.
00026 
00027    tclSadie is free software; you can redistribute it and/or modify it
00028    under the terms of the GNU General Public License as published by
00029    the Free Software Foundation; either version 2 of the License, or
00030    (at your option) any later version.
00031 
00032    tclSadie is distributed in the hope that it will be useful, but
00033    WITHOUT ANY WARRANTY; without even the implied warranty of
00034    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00035    General Public License for more details.
00036 
00037    You should have received a copy of the GNU General Public License
00038    along with tclSadie; if not, write to the Free Software Foundation,
00039    Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.  */
00040 
00041 #if HAVE_CONFIG_H
00042 #include <config.h>
00043 #endif /* HAVE_CONFIG_H */
00044 #include "logerr.h"
00045 #if HAVE_PTHREADS
00046 #include <pthread.h>
00048 #define POSIX_THREADS 1
00049 #else
00050 
00051 #define POSIX_THREADS 0
00052 #endif /* HAVE_PTHREADS */
00053 
00054 #include <unistd.h>
00055 #include <errno.h>
00056 #include <stdlib.h>
00057 #include <string.h>
00058 #include <inttypes.h>
00059 #include <sadie.h>
00060 #include "Sadie_Index.h"
00061 #if WITH_DMALLOC
00062 #include <dmalloc.h>
00063 #endif /* WITH_DMALLOC */
00064 
00065 static const int maxsize = 14; 
00066 static const int minsize = 4; 
00067 static const uint32_t fnv32hash_magic_init = 0x811c9dc5;  
00069 typedef struct Sad_property * sad_propertyp_t; 
00070 typedef struct Sad_docitem * sad_docitemp_t; 
00071 typedef struct Sad_doc * sad_docp_t;  
00072 typedef struct Sad_propertyitem * sad_propertyitemp_t; 
00075 struct Sad_doclist
00076 {
00077 #ifdef HAVE_PTHREADS
00078   pthread_mutex_t lock;  
00079 #else
00080   int lock[6];  
00081 #endif /* HAVE_PTHREADS */
00082   uint32_t log2nbuckets; 
00083   sad_docitemp_t *buckets; 
00084 };
00085 
00087 struct Sad_docitem
00088 {
00089   size_t keylen; 
00090   const char *key;  
00091   sad_docp_t doc;   
00092   sad_docitemp_t next;  
00093 };
00094 
00096 struct Sad_property
00097 {
00098   void *data; 
00099   sad_property_data_destructor_t datadestruct; 
00100 };
00101 
00103 struct Sad_propertyitem
00104 {
00105   size_t keylen; 
00106   const char *key;  
00107   sad_propertyp_t prop;  
00108   sad_propertyitemp_t next;  
00109 };
00110 
00112 struct Sad_doc
00113 {
00114   uint32_t log2nbuckets; 
00115   sad_propertyitemp_t *buckets; 
00116   const IMAGE *baseimg; 
00117 };
00118 
00119 #ifndef HAVE_PTHREADS
00120 
00124 static int pthread_mutex_lock (void * dummy) { return 0; }
00125 static int pthread_mutex_unlock (void * dummy) { return 0; }
00126 static int pthread_mutex_destroy (void * dummy) { return 0; }
00127 static int pthread_mutex_init (void * dummy1, void * dummy2) { return 0; }
00129 #endif
00130 
00141 static size_t
00142 hash_string (const char *str, const uint32_t log2len, size_t *slen) 
00143 {
00144   uint32_t hash;
00145   uint32_t mask;
00146   unsigned char* usp;
00147  
00148   logerr_assert (LOGERR_CRIT, LOGERR_FUNC, ((str != NULL) && (slen != NULL)));
00149   logerr_assert (LOGERR_DEBUG, LOGERR_FUNC,
00150                  ((minsize <= log2len) && (log2len <= maxsize)));
00151   hash = fnv32hash_magic_init;
00152   usp = (unsigned char *) str;
00153   *slen = 1; /* At least 1 (terminating null). */
00154   while (*usp)
00155     {
00156       (*slen)++;
00157       hash ^= (uint32_t) *usp++;
00158       hash += ((hash << 1) + (hash << 4) + (hash << 7)
00159                + (hash << 8) + (hash << 24));
00160     }
00161   mask = (1 << log2len) - 1;
00162   return (size_t) (hash & mask);
00163 }
00164 
00170 static void
00171 dispose_propertyitem (sad_propertyitemp_t thepropertyitem)
00172 {
00173   logerr_assert (LOGERR_CRIT, LOGERR_FUNC, (thepropertyitem != NULL));
00174   logerr_assert (LOGERR_DEBUG, LOGERR_FUNC,
00175                  ((thepropertyitem->key != NULL) == (thepropertyitem->keylen > 0)));
00176   free ((char *) thepropertyitem->key);
00177   if (thepropertyitem->prop != NULL)
00178     {
00179       logerr_assert (LOGERR_CRIT, LOGERR_FUNC,
00180                      (thepropertyitem->prop->datadestruct != NULL));
00181       (*(thepropertyitem->prop->datadestruct)) (thepropertyitem->prop->data);
00182       free (thepropertyitem->prop);
00183     }
00184   free (thepropertyitem);
00185 }
00186 
00194 static void
00195 dispose_doc (sad_docp_t thedoc)
00196 {
00197   size_t i, nbuckets;
00198   sad_propertyitemp_t *buck;
00199   sad_propertyitemp_t d, v;
00200 
00201   logerr_assert (LOGERR_CRIT, LOGERR_FUNC, (thedoc != NULL));
00202   RELIMG ((IMAGE**) &thedoc->baseimg);
00203   nbuckets = (size_t) (1 << thedoc->log2nbuckets);
00204   for (i = nbuckets, buck = thedoc->buckets; i; i--, buck++)
00205     {
00206       d = *buck;
00207       while (d)
00208         {
00209           v = d;
00210           d = d->next;
00211           dispose_propertyitem (v);
00212         }
00213     }
00214   free (thedoc->buckets);
00215   free (thedoc);
00216 }
00217 
00222 static void
00223 dispose_docitem (sad_docitemp_t thedocitem)
00224 {
00225   logerr_assert (LOGERR_CRIT, LOGERR_FUNC, (thedocitem != NULL));
00226   logerr_assert (LOGERR_DEBUG, LOGERR_FUNC,
00227                  ((thedocitem->key != NULL) == (thedocitem->keylen > 0)));
00228   free ((char *) thedocitem->key);
00229   if (thedocitem->doc != NULL)
00230     dispose_doc (thedocitem->doc);
00231   free (thedocitem);
00232 }
00233 
00240 void
00241 dispose_doclist (sad_doclistp_t thedoclist)
00242 {
00243   int err = 0;
00244   size_t i, nbuckets;
00245   sad_docitemp_t *buck;
00246   sad_docitemp_t d, v;
00247 
00248   if (thedoclist)
00249     {
00250       logerr_assert (LOGERR_DEBUG, LOGERR_FUNC,
00251                      ((thedoclist->buckets != NULL)
00252                       && (thedoclist->log2nbuckets >= minsize)
00253                       && (thedoclist->log2nbuckets <= maxsize)));
00254       if (POSIX_THREADS)
00255         {
00256           err = pthread_mutex_lock (&thedoclist->lock);
00257           if (err)
00258             {
00259               logerr_err (LOGERR_FUNC,
00260                           "could not acquire lock to dispose of doclist: error = %d",
00261                           err);
00262               return;
00263             }
00264         }
00265       nbuckets = (size_t) (1 << thedoclist->log2nbuckets);
00266       for (i = nbuckets, buck = thedoclist->buckets; i; i--, buck++)
00267         {
00268           d = *buck;
00269           while (d)
00270             {
00271               v = d;
00272               d = d->next;
00273               dispose_docitem (v);
00274             }
00275         }
00276       free (thedoclist->buckets);
00277       if (POSIX_THREADS)
00278         {
00279           err = pthread_mutex_unlock (&thedoclist->lock);
00280           if (err)
00281             {
00282               logerr_err (LOGERR_FUNC,
00283                           "could not release lock to dispose of doclist: error = %d",
00284                           err);
00285               return;
00286             }
00287           err = pthread_mutex_destroy (&thedoclist->lock);
00288           if (err)
00289             {
00290               logerr_err (LOGERR_FUNC,
00291                           "failed to destroy the doclist lock during disposal: error = %d",
00292                           err);
00293               return;
00294             }
00295         }
00296       free (thedoclist);
00297     }
00298 }      
00299 
00308 static sad_docp_t
00309 make_doc (int logpsize, const IMAGE *img)
00310 {
00311   size_t nbuckets;
00312   sad_docp_t newdoc = NULL;
00313 
00314   newdoc = malloc (sizeof (struct Sad_doc));
00315   if (newdoc)
00316     {
00317       if (logpsize < minsize)
00318         logpsize = minsize;
00319       if (logpsize > maxsize)
00320         logpsize = maxsize;
00321       newdoc->log2nbuckets = logpsize;
00322       nbuckets = (size_t) (1 << logpsize);
00323       newdoc->buckets = calloc (nbuckets, sizeof (sad_propertyitemp_t));
00324       if (newdoc->buckets != NULL)
00325         newdoc->baseimg = img;
00326       else
00327         {
00328           free (newdoc);
00329           newdoc = NULL;
00330         }
00331     }
00332   return newdoc;
00333 }
00334 
00344 sad_propertyp_t
00345 make_property (sad_property_data_destructor_t yourdestruct, void *yourdata)
00346 {
00347   sad_propertyp_t newproperty;
00348 
00349   logerr_assert (LOGERR_CRIT, LOGERR_FUNC,
00350                  ((yourdestruct != NULL) && (yourdata != NULL)));
00351   newproperty = malloc (sizeof (struct Sad_property));
00352   if (newproperty)
00353     {
00354       newproperty->data = yourdata;
00355       newproperty->datadestruct = yourdestruct;
00356     }
00357   return newproperty;
00358 }
00359  
00368 sad_doclistp_t
00369 make_doclist (int logsize)
00370 {
00371   int err = 0;
00372   size_t nbuckets;
00373   sad_doclistp_t thedoclist;
00374 
00375   thedoclist = malloc (sizeof (struct Sad_doclist));
00376   if (thedoclist)
00377     {
00378       if (POSIX_THREADS)
00379         {
00380           err = pthread_mutex_init (&thedoclist->lock, NULL);
00381           if (err)
00382             {
00383               logerr_err (LOGERR_FUNC,
00384                           "could not initialize the doclist lock: error = %d",
00385                           err);
00386               free (thedoclist);
00387               return NULL;
00388             }
00389         }
00390       if (logsize < minsize)
00391         logsize = minsize;
00392       if (logsize > maxsize)
00393         logsize = maxsize;
00394       thedoclist->log2nbuckets = logsize;
00395       nbuckets = (size_t) (1 << logsize);
00396       thedoclist->buckets = calloc (nbuckets, sizeof (sad_docitemp_t));
00397       if (thedoclist->buckets == NULL)
00398         {
00399           if (POSIX_THREADS)
00400             {
00401               err = pthread_mutex_destroy (&thedoclist->lock);
00402               if (err)
00403                 logerr_err (LOGERR_FUNC,
00404                             "failed to destroy the doclist lock during bucket allocation failure: error = %d",
00405                             err);
00406             }
00407           free (thedoclist);
00408           thedoclist = NULL;
00409         }
00410     }
00411   return thedoclist;
00412 }
00413 
00426 static sad_docitemp_t
00427 make_docitem (const size_t dkeylen, const char *dkey, const sad_docp_t docp,
00428               const sad_docitemp_t dinext)
00429 {
00430   sad_docitemp_t newitem;
00431   char *newkey;
00432 
00433   logerr_assert (LOGERR_CRIT, LOGERR_FUNC,
00434                  ((dkeylen > 0) && (dkey != NULL) && (docp != NULL)));
00435   newitem = malloc (sizeof (struct Sad_docitem));
00436   if (newitem)
00437     {
00438       newkey = calloc (dkeylen, 1);
00439       if ((newkey == NULL) || (strncpy (newkey, dkey, dkeylen) == NULL))
00440         {
00441           free (newitem);
00442           newitem = NULL;
00443         }
00444       else
00445         {
00446           newitem->keylen = dkeylen;
00447           newitem->key = (const char *) newkey;
00448           newitem->doc = docp;
00449           newitem->next = dinext;
00450         }
00451     }
00452   return newitem;
00453 }
00454 
00467 static sad_propertyitemp_t
00468 make_propertyitem (const size_t pkeylen, const char *pkey,
00469                    const sad_propertyp_t property,
00470                    const sad_propertyitemp_t pinext)
00471 {
00472   sad_propertyitemp_t newitem;
00473   char *newkey;
00474 
00475   logerr_assert (LOGERR_CRIT, LOGERR_FUNC,
00476                  ((pkeylen > 0) && (pkey != NULL) && (property != NULL)));
00477   newitem = malloc (sizeof (struct Sad_propertyitem));
00478   if (newitem)
00479     {
00480       newkey = calloc (pkeylen, 1);
00481       if ((newkey == NULL) || (strncpy (newkey, pkey, pkeylen) == NULL))
00482         {
00483           free (newitem);
00484           newitem = NULL;
00485         }
00486       else
00487         {
00488           newitem->keylen = pkeylen;
00489           newitem->key = (const char *) newkey;
00490           newitem->prop = property;
00491           newitem->next = pinext;
00492         }
00493     }
00494   return newitem;
00495 }
00496 
00513 int
00514 sad_put_doc (sad_doclistp_t doclist, const char *dkey,
00515              int logpsize, const IMAGE *img)
00516 {
00517   int err = 0;
00518   int failure = 0;
00519   sad_docp_t newdoc;
00520   size_t dkeylen;
00521   size_t hashval;
00522   sad_docitemp_t *dihandle;
00523   sad_docitemp_t newitem;
00524   int uninserted;
00525   int order;
00526 
00527   logerr_assert (LOGERR_CRIT, LOGERR_FUNC,
00528                  ((doclist != NULL) && (dkey != NULL)));
00529   logerr_assert (LOGERR_DEBUG, LOGERR_FUNC,
00530                  ((minsize <= doclist->log2nbuckets)
00531                   && (doclist->log2nbuckets <= maxsize)));
00532   newdoc = make_doc (logpsize, img);
00533   logerr_assert (LOGERR_CRIT, LOGERR_FUNC, (newdoc != NULL));
00534   if (POSIX_THREADS)
00535     {
00536       err = pthread_mutex_lock (&doclist->lock);
00537       if (err)
00538         {
00539           logerr_err (LOGERR_FUNC,
00540                       "could not acquire lock to insert doc %s: error = %d",
00541                       dkey, err);
00542           return err;
00543         }
00544     }
00545   uninserted = 1;
00546   hashval = hash_string (dkey, doclist->log2nbuckets, &dkeylen);
00547   dihandle = &doclist->buckets[hashval];
00548   while ((*dihandle != NULL) && uninserted)
00549     {
00550       order = strcmp (dkey, (*dihandle)->key);
00551       if (order > 0)
00552         dihandle = &(*dihandle)->next;
00553       else
00554         {
00555           if (order < 0)
00556             newitem = make_docitem (dkeylen, dkey, newdoc, *dihandle);
00557           else
00558             {            
00559               newitem = make_docitem (dkeylen, dkey, newdoc,
00560                                       (*dihandle)->next);
00561               dispose_docitem (*dihandle);
00562             }
00563           failure = (newitem == NULL);
00564           uninserted = 0;
00565           *dihandle = newitem;
00566           dihandle = &newitem->next;
00567         }
00568     }
00569   if (uninserted)
00570     {
00571       logerr_assert (LOGERR_DEBUG, LOGERR_FUNC, (*dihandle == NULL));      
00572       *dihandle = make_docitem (dkeylen, dkey, newdoc, NULL);
00573     }
00574   if (POSIX_THREADS)
00575     {
00576       err = pthread_mutex_unlock (&doclist->lock);
00577       if (err)
00578         logerr_err (LOGERR_FUNC,
00579                     "could not release lock to insert doc %s: error = %d",
00580                     dkey, err);
00581     }
00582   return (failure) ? failure : err;
00583 }
00584 
00595 int
00596 sad_dispose_doc (sad_doclistp_t doclist, const char *dkey)
00597 {
00598   int err = 0;
00599   size_t dkeylen;
00600   size_t hashval;
00601   sad_docitemp_t *dihandle;
00602   sad_docitemp_t tail;
00603   int order;
00604 
00605   logerr_assert (LOGERR_CRIT, LOGERR_FUNC,
00606                  ((doclist != NULL) && (dkey != NULL)));
00607   logerr_assert (LOGERR_DEBUG, LOGERR_FUNC,
00608                  ((minsize <= doclist->log2nbuckets)
00609                   && (doclist->log2nbuckets <= maxsize)));
00610   if (POSIX_THREADS)
00611     {
00612       err = pthread_mutex_lock (&doclist->lock);
00613       if (err)
00614         {
00615           logerrno (LOGERR_ERR, err, LOGERR_FUNC,
00616                     "could not acquire the lock to delete doc %s",
00617                     dkey);
00618           return err;
00619         }
00620     }
00621   order = 1;
00622   hashval = hash_string (dkey, doclist->log2nbuckets, &dkeylen);
00623   dihandle = &doclist->buckets[hashval];
00624   while ((*dihandle != NULL) && (order > 0))
00625     {
00626       order = strcmp (dkey, (*dihandle)->key);
00627       if (order > 0)
00628         dihandle = &(*dihandle)->next;
00629       else if (order == 0)
00630         {
00631           tail = (*dihandle)->next;
00632           dispose_docitem (*dihandle);
00633           *dihandle = tail;
00634         }
00635     }
00636   if (order > 0)
00637     logerr_warning (LOGERR_FUNC,
00638                     "could not find the item to be deleted: doc=%s",
00639                     dkey);
00640   if (POSIX_THREADS)
00641     {
00642       err = pthread_mutex_unlock (&doclist->lock);
00643       if (err)
00644         logerrno (LOGERR_ERR, err, LOGERR_FUNC,
00645                   "could not release the lock after deleting doc %s",
00646                   dkey);
00647     }
00648   return (order > 0) ? -1 : err;
00649 }
00650 
00664 static int
00665 put_docitem_property (sad_docitemp_t docitem,
00666                       const char *pkey, const sad_propertyp_t prop)
00667 {
00668   int err = 0;
00669   size_t pkeylen;
00670   size_t hashval;
00671   sad_propertyitemp_t *pihandle;
00672   sad_propertyitemp_t newitem;
00673   int order;
00674   int uninserted = 1;
00675 
00676   logerr_assert (LOGERR_CRIT, LOGERR_FUNC,
00677                  ((docitem != NULL) && (pkey != NULL) && (prop != NULL)));
00678   logerr_assert (LOGERR_DEBUG, LOGERR_FUNC,
00679                  ((minsize <= docitem->doc->log2nbuckets)
00680                   && (docitem->doc->log2nbuckets <= maxsize)));
00681   hashval = hash_string (pkey, docitem->doc->log2nbuckets, &pkeylen);
00682   pihandle = &docitem->doc->buckets[hashval];
00683   while ((*pihandle != NULL) && uninserted)
00684     {
00685       order = strcmp (pkey, (*pihandle)->key);
00686       if (order > 0)
00687         pihandle = &(*pihandle)->next;
00688       else
00689         {
00690           if (order < 0)
00691             newitem = make_propertyitem (pkeylen, pkey, prop, *pihandle);
00692           else
00693             {            
00694               newitem = make_propertyitem (pkeylen, pkey, prop, (*pihandle)->next);
00695               if (newitem)
00696                 dispose_propertyitem (*pihandle);
00697             }
00698           if (newitem == NULL)
00699             return -1;
00700           uninserted = 0;
00701           *pihandle = newitem;
00702           pihandle = &newitem->next;
00703         }
00704     }
00705   if (uninserted)
00706     {
00707       logerr_assert (LOGERR_DEBUG, LOGERR_FUNC, (*pihandle == NULL));      
00708       *pihandle = make_propertyitem (pkeylen, pkey, prop, NULL);
00709       err = (*pihandle == NULL);
00710     }
00711   return err;  
00712 }
00713 
00722 static sad_propertyp_t
00723 get_docitem_property (sad_docitemp_t docitem, const char *pkey)
00724 {
00725   size_t pkeylen;
00726   size_t hashval;
00727   sad_propertyitemp_t pip;
00728   sad_propertyp_t theprop = NULL;
00729   int compare;
00730 
00731   logerr_assert (LOGERR_CRIT, LOGERR_FUNC, ((docitem != NULL) && (pkey != NULL)));
00732   logerr_assert (LOGERR_DEBUG, LOGERR_FUNC,
00733                  ((minsize <= docitem->doc->log2nbuckets)
00734                   && (docitem->doc->log2nbuckets <= maxsize)));
00735   hashval = hash_string (pkey, docitem->doc->log2nbuckets, &pkeylen);
00736   pip = docitem->doc->buckets[hashval];
00737   compare = -1;
00738   while ((pip != NULL) && (compare = strcmp (pkey, pip->key)) != 0)
00739     pip = pip->next;
00740   if (pip != NULL)
00741     theprop = pip->prop;
00742   return theprop;
00743 }
00744 
00764 int
00765 sad_put_doc_property (sad_doclistp_t doclist, const char *dkey,
00766                       const char *pkey,
00767                       sad_property_data_destructor_t destruct,
00768                       void *data)
00769 {
00770   int err = 0;
00771   int failure = 0;
00772   size_t hashval;
00773   size_t dkeylen;
00774   sad_docitemp_t dip;
00775   sad_propertyp_t prop;
00776   int compare;
00777 
00778   logerr_assert (LOGERR_CRIT, LOGERR_FUNC,
00779                  ((doclist != NULL) && (dkey != NULL)
00780                   && (pkey != NULL)));
00781   logerr_assert (LOGERR_DEBUG, LOGERR_FUNC,
00782                  ((minsize <= doclist->log2nbuckets)
00783                   && (doclist->log2nbuckets <= maxsize)));
00784   prop = make_property (destruct, data);
00785   if (prop == NULL)
00786     {
00787       logerr_err (LOGERR_FUNC,
00788                   "could not create a property: doc = %s, prop = %s",
00789                   dkey, pkey);
00790       return -1;
00791     }
00792   if (POSIX_THREADS)
00793     {
00794       err = pthread_mutex_lock (&doclist->lock);
00795       if (err)
00796         {
00797           logerr_err (LOGERR_FUNC,
00798                       "could not acquire lock to set a property: doc = %s, prop = %s, error = %d",
00799                       dkey, pkey, err);
00800           return err;
00801         }
00802     }
00803   hashval = hash_string (dkey, doclist->log2nbuckets, &dkeylen);
00804   dip = doclist->buckets[hashval];
00805   compare = -1;
00806   while ((dip != NULL) && (compare = strcmp (dkey, dip->key)) != 0)
00807     dip = dip->next;
00808   if (dip != NULL)
00809     failure = put_docitem_property (dip, pkey, prop);
00810   else
00811     {
00812       logerr_err (LOGERR_FUNC,
00813                   "could not find the document to set a property: doc = %s, prop = %s, hv = %d",
00814                   dkey, pkey, hashval);
00815       failure = -1;
00816     }
00817   if (POSIX_THREADS)
00818     {
00819       err = pthread_mutex_unlock (&doclist->lock);
00820       if (err)
00821         logerr_err (LOGERR_FUNC,
00822                     "could not release lock to set a property: doc = %s, prop = %s, error = %d",
00823                     dkey, pkey, err);
00824     }
00825   return (failure) ? failure : err;
00826 }
00827 
00841 void *
00842 sad_get_doc_property (const sad_doclistp_t doclist, const char *dkey,
00843                       const char *pkey)
00844 {
00845   int err = 0;
00846   sad_propertyp_t theprop = NULL;
00847   size_t hashval;
00848   size_t dkeylen;
00849   sad_docitemp_t dip;
00850   int compare;
00851 
00852   logerr_assert (LOGERR_CRIT, LOGERR_FUNC,
00853                  ((doclist != NULL) && (dkey != NULL) && (pkey != NULL)));
00854   logerr_assert (LOGERR_DEBUG, LOGERR_FUNC,
00855                  ((minsize <= doclist->log2nbuckets)
00856                   && (doclist->log2nbuckets <= maxsize)));
00857   if (POSIX_THREADS)
00858     {
00859       err = pthread_mutex_lock (&doclist->lock);
00860       if (err)
00861         {
00862           logerr_err (LOGERR_FUNC,
00863                       "could not acquire lock to get a property: doc = %s, prop = %s, error = %d",
00864                       dkey, pkey, err);
00865           return NULL;
00866         }
00867     }
00868   hashval = hash_string (dkey, doclist->log2nbuckets, &dkeylen);
00869   dip = doclist->buckets[hashval];
00870   compare = -1;
00871   while ((dip != NULL) && ((compare = strcmp (dkey, dip->key)) != 0))
00872     dip = dip->next;
00873   if (dip != NULL)
00874     theprop = get_docitem_property (dip, pkey);
00875   else
00876     logerr_err (LOGERR_FUNC,
00877                 "could not find the document to get a property: doc = %s, prop = %s, hv = %d",
00878                 dkey, pkey, hashval);
00879   if (POSIX_THREADS)
00880     {
00881       err = pthread_mutex_unlock (&doclist->lock);
00882       if (err)
00883         logerr_err (LOGERR_FUNC,
00884                     "could not release lock to get a property: doc = %s, prop = %s, error = %d",
00885                     dkey, pkey, err);
00886     }
00887   return (err || (theprop == NULL)) ? NULL : theprop->data;
00888 }
00889 
00890       

Generated on Fri Jul 8 14:55:01 2005 for tclSadie by  doxygen 1.4.2