Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Class Members | File Members | Related Pages

NVcontainer Class Reference

#include <NVcontainer.h>

Inheritance diagram for NVcontainer:

NVArray NVlist NVNewsgroup NVHash NVList CNewsgroup NVActiveDB List of all members.

Public Types

enum  { UnLock = F_UNLCK, ShrdLock = F_RDLCK, ExclLock = F_WRLCK }
enum  { Block = 0x0, NoBlock = 0x1 }

Public Member Functions

int lock (int command, int block=Block)
int get_lock (void)
virtual void open (const char *dbname, int flags=0)
virtual int is_open (void)
virtual void close (void)
void rename_to_bad_and_close (void)
void setmtime (nvtime_t tm, int force=0)
void getmtime (nvtime_t *tm)

Protected Member Functions

 NVcontainer (void)
 NVcontainer (const char *dbname, int flags=0)
virtual ~NVcontainer (void)
virtual void make_current (void)
virtual int is_current (void)
virtual size_t resize (size_t nsz)
nvoff_t getdata ()
nvoff_t getdatap ()
void setdata (nvoff_t d)
nvoff_t nvalloc (size_t rsz)
void nvfree (nvoff_t f)

Protected Attributes

char * mem_p
size_t mem_sz

Private Member Functions

FreeListo2fl (nvoff_t o)
nvoff_t fl2o (FreeList *r)

Private Attributes

int lck_stack [NVcontainer_LOCKSTACKSIZE]
int lck_stackp
char mem_fn [MAXPATHLEN]
int mem_fd
Headermem_hdr

Detailed Description

Author:
Thomas Gschwind How should we define a uniform interface to access data stored within an NVcontainer? Two kinds of accesses exist: shared access ... uses NVcontainer's data copy copy access ... copies the data at each request The second version is easier to use, but reduces the performance.

Bug:
Documentation is missing.

Definition at line 29 of file NVcontainer.h.


Member Enumeration Documentation

anonymous enum
 

Enumeration values:
UnLock 
ShrdLock 
ExclLock 

Definition at line 98 of file NVcontainer.h.

00098              {
00099                 UnLock = F_UNLCK,
00100                 ShrdLock = F_RDLCK,
00101                 ExclLock = F_WRLCK
00102         };

anonymous enum
 

Enumeration values:
Block 
NoBlock 

Definition at line 103 of file NVcontainer.h.

00103              {
00104                 Block = 0x0,
00105                 NoBlock = 0x1
00106         };


Constructor & Destructor Documentation

NVcontainer::NVcontainer void   )  [protected]
 

Definition at line 102 of file NVcontainer.cc.

References lck_stackp, mem_fd, mem_fn, mem_hdr, mem_p, and NVcontainer_LOCKSTACKSIZE.

00103 {
00104         lck_stackp = NVcontainer_LOCKSTACKSIZE;
00105         mem_fn[0] = '\0';
00106         mem_fd = -1;
00107         mem_p = NULL;
00108         mem_hdr = (Header *) mem_p;
00109 }

NVcontainer::NVcontainer const char *  dbname,
int  flags = 0
[protected]
 

Definition at line 111 of file NVcontainer.cc.

References lck_stackp, mem_fd, NVcontainer_LOCKSTACKSIZE, and open().

00112 {
00113         lck_stackp = NVcontainer_LOCKSTACKSIZE;
00114         mem_fd = -1;
00115         open(dbname, flags);
00116 }

NVcontainer::~NVcontainer void   )  [protected, virtual]
 

Definition at line 118 of file NVcontainer.cc.

References close().

00119 {
00120         close();
00121 }


Member Function Documentation

void NVcontainer::close void   )  [virtual]
 

Reimplemented in NVActiveDB.

Definition at line 705 of file NVcontainer.cc.

References lck_stackp, mem_fd, mem_fn, mem_hdr, mem_p, mem_sz, NVcontainer_LOCKSTACKSIZE, slog, and VERB.

Referenced by NVActiveDB::close(), nvfree(), open(), rename_to_bad_and_close(), and ~NVcontainer().

00706 {
00707         if (mem_fd < 0)
00708                 return;
00709         munmap(mem_p, mem_sz);
00710         ::close(mem_fd);
00711         if (lck_stackp != NVcontainer_LOCKSTACKSIZE) {
00712                 VERB(slog.
00713                      p(Logger::
00714                        Critical) <<
00715                      "NVcontainer::close: Forgot to unlock the container before closing it!\n");
00716                 lck_stackp = NVcontainer_LOCKSTACKSIZE;
00717         }
00718         mem_fn[0] = '\0';
00719         mem_fd = -1;
00720         mem_p = NULL;
00721         mem_hdr = (Header *) mem_p;
00722 }

nvoff_t NVcontainer::fl2o FreeList r  )  [inline, private]
 

Definition at line 62 of file NVcontainer.h.

References mem_p, and nvoff_t.

Referenced by nvalloc(), and nvfree().

00062                                    {
00063                 return r ? (char *) r - mem_p : 0;
00064         }

int NVcontainer::get_lock void   ) 
 

Reimplemented in NVActiveDB.

Definition at line 603 of file NVcontainer.cc.

References lck_stack, lck_stackp, NVcontainer_LOCKSTACKSIZE, and UnLock.

Referenced by NVActiveDB::get_lock().

00604 {
00605         return lck_stackp <
00606             NVcontainer_LOCKSTACKSIZE ? lck_stack[lck_stackp] : UnLock;
00607 }

nvoff_t NVcontainer::getdata  )  [protected]
 

Definition at line 236 of file NVcontainer.cc.

References mem_hdr, nvoff_t, and NVcontainer::Header::userdata.

Referenced by NVListIter::attach(), NVHash::make_current(), NVArray::make_current(), NVList::remove(), and NVArray::ssetsize().

00237 {
00238         return mem_hdr->userdata;
00239 }

nvoff_t NVcontainer::getdatap  )  [protected]
 

Definition at line 241 of file NVcontainer.cc.

References mem_hdr, mem_p, nvoff_t, and NVcontainer::Header::userdata.

Referenced by NVList::append(), NVList::clear(), NVList::is_empty(), NVList::prepend(), NVList::print(), and NVList::remove().

00242 {
00243         return ((char *) &mem_hdr->userdata - mem_p);
00244 }

void NVcontainer::getmtime nvtime_t tm  ) 
 

Definition at line 748 of file NVcontainer.cc.

References lock(), mem_hdr, NVcontainer::Header::mtime, nvtime_t, ShrdLock, and UnLock.

Referenced by NVActiveDB::getmtime(), and CNewsgroup::updateOverview().

00749 {
00750         lock(ShrdLock);
00751         (*tm) = mem_hdr->mtime;
00752         lock(UnLock);
00753 }

virtual int NVcontainer::is_current void   )  [inline, protected, virtual]
 

Definition at line 86 of file NVcontainer.h.

References mem_hdr, mem_sz, and NVcontainer::Header::size.

Referenced by NVHash::make_current(), make_current(), and NVArray::make_current().

00086                                      {
00087                 return mem_sz == mem_hdr->size;
00088         }

int NVcontainer::is_open void   )  [virtual]
 

Reimplemented in NVActiveDB.

Definition at line 700 of file NVcontainer.cc.

References mem_fd.

Referenced by NVActiveDB::is_open().

00701 {
00702         return mem_fd >= 0;
00703 }

int NVcontainer::lock int  command,
int  block = Block
 

Reimplemented in NVActiveDB.

Definition at line 550 of file NVcontainer.cc.

References ERROR_LOCATION, ExclLock, lck_stack, lck_stackp, make_current(), mem_fd, NoBlock, NVcontainer_LOCKSTACKSIZE, nvflock(), and UnLock.

Referenced by NVHash::add(), NVList::append(), NVListIter::attach(), NVHashIter::attach(), NVList::clear(), NVHash::clear(), NVArray::clear(), NVArray::del(), NVListIter::detach(), NVHashIter::detach(), NVArray::get(), NVNewsgroup::getarticle(), getmtime(), NVNewsgroup::getover(), NVArray::has_element(), NVList::is_empty(), NVHash::is_empty(), NVArray::is_empty(), NVActiveDB::lock(), nvalloc(), nvfree(), NVHash::open(), CNewsgroup::prefetchGroup(), CNewsgroup::prefetchOverview(), NVList::prepend(), NVList::print(), NVHash::print(), NVArray::print(), NVNewsgroup::printarticle(), NVNewsgroup::printheaderdb(), NVNewsgroup::printlistgroup(), NVNewsgroup::printover(), NVNewsgroup::printoverdb(), NVNewsgroup::readoverdb(), NVList::remove(), resize(), NVArray::set(), NVNewsgroup::setarticle(), setmtime(), NVNewsgroup::setover(), NVNewsgroup::setsize(), NVArray::setsize(), CNewsgroup::setsize(), and CNewsgroup::updateOverview().

00551 {
00552         int res;
00553         int curLock = UnLock;
00554 
00555         if (lck_stackp < NVcontainer_LOCKSTACKSIZE) {
00556                 curLock = lck_stack[lck_stackp];
00557         }
00558         if (command == UnLock) {
00559                 // Unlock container 
00560                 if (lck_stackp >= NVcontainer_LOCKSTACKSIZE) {
00561                         throw
00562                             Error
00563                             ("NVContainer::lock(): Lock Stack underflow",
00564                              ERROR_LOCATION);
00565                 }
00566                 lck_stackp++;
00567                 command =
00568                     lck_stackp <
00569                     NVcontainer_LOCKSTACKSIZE ? lck_stack[lck_stackp] :
00570                     UnLock;
00571         } else {
00572                 // Lock container
00573                 if (lck_stackp == 0) {
00574                         throw
00575                             Error
00576                             ("NVContainer::lock(): Lock Stack overflow",
00577                              ERROR_LOCATION);
00578                 }
00579                 // Is already locked with excl => new lock must be excl
00580                 if (curLock == ExclLock)
00581                         command = ExclLock;
00582                 lck_stack[--lck_stackp] = command;
00583         }
00584         // Relock if lock state changed
00585         if (curLock != command) {
00586                 if ((res = nvflock(mem_fd, command, block)) < 0) {
00587                         if (errno == EWOULDBLOCK && block == NoBlock) {
00588                                 lck_stackp++;
00589                                 return -1;
00590                         }
00591                         throw
00592                             SystemError("NVContainer::lock(): flock failed",
00593                                         errno, ERROR_LOCATION);
00594                 }
00595                 // Adapt to the new size if somebody changed the container's 
00596                 // size
00597                 if (command != UnLock)
00598                         make_current();
00599         }
00600         return 0;
00601 }

void NVcontainer::make_current void   )  [protected, virtual]
 

Reimplemented in NVArray, and NVHash.

Definition at line 123 of file NVcontainer.cc.

References ERROR_LOCATION, NVcontainer::Header::hlen, is_current(), mem_fd, mem_fn, mem_hdr, mem_p, mem_sz, nvoff_t, Logger::p(), rename_to_bad_and_close(), NVcontainer::Header::size, slog, and NVcontainer::Header::version.

Referenced by lock(), NVHash::make_current(), NVArray::make_current(), open(), and resize().

00124 {
00125         struct stat st;
00126 
00127         if (mem_p) {
00128                 if (is_current())
00129                         return;
00130                 munmap(mem_p, mem_sz);
00131         }
00132 
00133         if (fstat(mem_fd, &st) < 0) {
00134                 throw SystemError("NVContainer(20801): fstat failed",
00135                                   errno, ERROR_LOCATION);
00136         }
00137 
00138         if ((nvoff_t) st.st_size <=
00139             (nvoff_t) sizeof(Header) + (nvoff_t) sizeof(FreeList)) {
00140 #ifdef HAVE_SSTREAM
00141                 stringstream sb;
00142 #else
00143                 strstream sb;
00144 #endif
00145                 sb << "NVConatiner::make_current(): info-record shrunk;"
00146                    << " mem_fn: " << ((mem_fn==NULL)? ("NULL") : (mem_fn))
00147                    << " st.st_size: " << (unsigned long int) st.st_size
00148                    << " sizeof(Header): " << (unsigned long int) sizeof(Header);
00149                 throw Error(sb.rdbuf()->str(), ERROR_LOCATION);
00150         }
00151 
00152         mem_sz = st.st_size;
00153         mem_p = (char *) mmap(NULL, mem_sz,
00154                               PROT_READ | PROT_WRITE, MAP_SHARED,
00155                               mem_fd, 0);
00156         if (mem_p == (char *) -1) {
00157                 mem_p = NULL;
00158                 throw SystemError("NVContainer::make_current(): mmap failed", errno,
00159                                   ERROR_LOCATION);
00160         }
00161         mem_hdr = (Header *) mem_p;
00162         //Do some sanity checks on the database
00163         if (mem_hdr->hlen != sizeof(Header)) {
00164 #ifdef HAVE_SSTREAM
00165                 stringstream sb;
00166 #else
00167                 strstream sb;
00168 #endif
00169                 sb << "NVConatiner::make_current(): wrong header size"
00170                    << " mem_fn: " << ((mem_fn==NULL)? ("NULL") : (mem_fn))
00171                    << " mem_hdr->hlen: " << (unsigned long int) mem_hdr->hlen
00172                    << " sizeof(Header): " << (unsigned long int) sizeof(Header);
00173                 rename_to_bad_and_close(); // close manipulate the member structure !!
00174                 throw Error(sb.rdbuf()->str(), ERROR_LOCATION);
00175         }
00176         if (mem_hdr->version != 2) {
00177 #ifdef HAVE_SSTREAM
00178                 stringstream sb;
00179 #else
00180                 strstream sb;
00181 #endif
00182                 sb << "NVConatiner::make_current(): wrong header version"
00183                    << " mem_fn: " << ((mem_fn==NULL)? ("NULL") : (mem_fn))
00184                    << " mem_hdr->version: " << (unsigned long int) mem_hdr->version;
00185                 rename_to_bad_and_close(); // close manipulate the member structure !!
00186                 throw Error(sb.rdbuf()->str(), ERROR_LOCATION);
00187         }
00188         if (mem_sz != mem_hdr->size) {
00189 #ifdef HAVE_SSTREAM
00190                 stringstream sb;
00191 #else
00192                 strstream sb;
00193 #endif
00194                 sb << "NVConatiner::make_current(): wrong database size stored "
00195                    << "in db-header - may be a hazard"
00196                    << " mem_fn: " << ((mem_fn==NULL)? ("NULL") : (mem_fn))
00197                    << " mem_sz: " << (unsigned long int) mem_sz
00198                    << " mem_hdr->size: " << (unsigned long int) mem_hdr->size;
00199                 slog.p(Logger::Critical) << sb.rdbuf()->str();
00200         }
00201 }

nvoff_t NVcontainer::nvalloc size_t  rsz  )  [protected]
 

Definition at line 251 of file NVcontainer.cc.

References ASSERT, NVcontainer::Header::bytes_free, ERROR_LOCATION, ExclLock, fl2o(), NVcontainer::Header::freelist, lock(), mem_hdr, mem_p, mem_sz, NVcontainer::FreeList::next, nvoff_t, o2fl(), Logger::p(), resize(), NVcontainer::FreeList::size, slog, UnLock, and VERB.

Referenced by NVHash::open(), NVlist::sappend(), NVNewsgroup::setarticle(), NVNewsgroup::setover(), NVlist::sprepend(), NVArray::sset(), and NVArray::ssetsize().

00252 {
00253         lock(ExclLock);
00254         FreeList *flhead = o2fl(mem_hdr->freelist);
00255         FreeList *cur, *prv, *res;
00256 
00257         // The allocated memory block has to meet several requirements
00258         // * aligned on 16 Byte boundary
00259         // * size has to be a multiple of 16 (simplifies the alignment)
00260         // * the allocated block has to hold its size
00261         //   the memory after the size indicator will be returned
00262         rsz = (rsz + sizeof(unsigned long) + 0xf) & (~0xf);
00263         if (flhead == NULL) {
00264                 throw Error ("NVContainer(5946): Database file corrupted (freelist==NULL)",
00265                      ERROR_LOCATION);
00266         }
00267         // flhead points to the last free memory block available in the database
00268         prv = flhead;
00269         cur = o2fl(prv->next);
00270         // find the first suitable memory block in the database
00271         while (cur->size < rsz && cur != flhead) {
00272                 prv = cur;
00273                 cur = o2fl(cur->next);
00274         }
00275 
00276         if (cur == flhead) {
00277                 // Special care has to be taken for the last free memory block
00278                 // It must always be present! So we have to resize it, if its
00279                 // memory is smaller than the requested size plus the size 
00280                 // necessary to maintain the last block of free memory.
00281                 if (flhead->size < rsz + sizeof(FreeList)) {
00282                         nvoff_t prvoff = fl2o(prv);
00283                         // Since it is very likely that the mapped region will change
00284                         // during the resize operation, we will have to save the
00285                         // currently used pointers
00286                         int needsz = rsz + sizeof(FreeList) - flhead->size;
00287                         resize(mem_sz + needsz);
00288                         cur = flhead = o2fl(mem_hdr->freelist);
00289                         prv = o2fl(prvoff);
00290                         ASSERT(if (cur->size < rsz + sizeof(FreeList)) {
00291                                throw
00292                                AssertionError
00293                                ("NVContainer::nvalloc: resize failed",
00294                                 ERROR_LOCATION);}
00295                         );
00296                 }
00297         }
00298         ASSERT(if (cur->size < rsz) {
00299                throw
00300                AssertionError
00301                ("NVContainer::nvalloc: did not find a large enough free memory block",
00302                 ERROR_LOCATION);}
00303         );
00304 
00305         res = cur;
00306 
00307         if (cur->size < rsz + sizeof(FreeList)) {
00308                 // The available space is too small to split?
00309                 // This may only occur if cur _is_not_ the tail of the free blocks
00310                 ASSERT(if (res == flhead) {
00311                        throw
00312                        AssertionError
00313                        ("NVContainer::nvalloc: Cannot split block of free memory at tail of database",
00314                         ERROR_LOCATION);}
00315                 );
00316                 prv->next = cur->next;
00317                 rsz = cur->size;
00318         } else {
00319                 // Split the space into two parts
00320                 cur = (FreeList *) ((char *) cur + rsz);
00321                 cur->size = res->size - rsz;
00322                 if (prv != res) {
00323                         // list contains at least two blocks
00324                         cur->next = res->next;
00325                         prv->next = fl2o(cur);
00326                         if (res == flhead) {
00327                                 mem_hdr->freelist = fl2o(cur);
00328                         }
00329                 } else {
00330                         // list contains only one block pointing to itself
00331                         // this must be the free memory block at the tail
00332                         ASSERT(if (res != flhead) {
00333                                throw
00334                                AssertionError
00335                                ("NVList::nvalloc: Lost block of free memory at tail of database",
00336                                 ERROR_LOCATION);}
00337                         );
00338                         mem_hdr->freelist = cur->next = fl2o(cur);
00339                 }
00340         }
00341         mem_hdr->bytes_free -= rsz;
00342         lock(UnLock);
00343 
00344         *(unsigned long *) res = rsz;
00345 #ifdef FREELIST_ASSERT_ON
00346         char buf[256];
00347         int i = 10000;
00348         prv = flhead = o2fl(mem_hdr->freelist);;
00349         cur = o2fl(prv->next);
00350 
00351         VERB(sprintf
00352              (buf, "nvalloc: checking freelist flhead=%p\n", flhead);
00353              slog.p(Logger::Debug) << buf);
00354         while (cur != flhead && i) {
00355                 VERB(sprintf
00356                      (buf, "nvalloc: elem(%lu)={%lu,%lu}\n",
00357                       (nvoff_t) ((char *) cur - mem_p), cur->next,
00358                       cur->size); slog.p(Logger::Debug) << buf);
00359                 prv = cur;
00360                 cur = o2fl(cur->next);
00361                 ASSERT(if (prv >= cur) {
00362                        throw
00363                        AssertionError
00364                        ("NVContainer::nvalloc: freelist out of order!",
00365                         ERROR_LOCATION);}
00366                 );
00367                 i--;
00368         }
00369         VERB(sprintf
00370              (buf, "nvfree: tail(%lu)={%lu,%lu}\n",
00371               (nvoff_t) ((char *) cur - mem_p), cur->next, cur->size);
00372              slog.p(Logger::Debug) << buf);
00373         if (!i)
00374                 VERB(slog.
00375                      p(Logger::
00376                        Debug) <<
00377                      "nvalloc: more than 10000 free blocks!\n");
00378 #endif
00379         return (nvoff_t) ((char *) res - mem_p) + sizeof(unsigned long);
00380 }

void NVcontainer::nvfree nvoff_t  f  )  [protected]
 

Definition at line 382 of file NVcontainer.cc.

References ASSERT, NVcontainer::Header::bytes_free, close(), ERROR_LOCATION, ExclLock, fl2o(), NVcontainer::Header::freelist, lock(), mem_hdr, mem_p, mem_sz, NVcontainer::FreeList::next, nvoff_t, o2fl(), Logger::p(), NVcontainer::FreeList::size, slog, UnLock, and VERB.

Referenced by CNewsgroup::prefetchGroup(), NVArray::sclear(), NVArray::sdel(), NVNewsgroup::setarticle(), NVNewsgroup::setsize(), NVArray::setsize(), NVlist::sremove(), NVArray::sset(), NVArray::ssetsize(), and CNewsgroup::sUpdateOverview().

00383 {
00384 #ifdef FREELIST_ASSERT_ON
00385         VERB(char buf[256];
00386              sprintf(buf, "NVcontainer::nvfree(%lu)\n", p);
00387              slog.p(Logger::Debug) << buf);
00388 #endif
00389         lock(ExclLock);
00390 
00391         FreeList *pb, *pe;
00392         int psz;
00393 #ifdef FREELIST_ASSERT_ON
00394         FreeList *flhead;
00395         FreeList *cur, *prv;
00396         int i = 10000;
00397         prv = flhead = o2fl(mem_hdr->freelist);;
00398         cur = o2fl(prv->next);
00399 
00400         VERB(sprintf(buf, "NVContainer::nvfree: checking freelist flhead=%p\n", flhead);
00401              slog.p(Logger::Debug) << buf);
00402         while (cur != flhead && i) {
00403                 VERB(sprintf
00404                      (buf, "NVContainer::nvfree: elem(%lu)={%lu,%lu}\n",
00405                       (nvoff_t) ((char *) cur - mem_p), cur->next,
00406                       cur->size); slog.p(Logger::Debug) << buf);
00407                 prv = cur;
00408                 cur = o2fl(cur->next);
00409                 ASSERT(if (prv >= cur) {
00410                        throw
00411                        AssertionError
00412                        ("NVContainer::nvfree: freelist out of order!",
00413                         ERROR_LOCATION);}
00414                 );
00415                 i--;
00416         }
00417         VERB(sprintf
00418              (buf, "NVContainer::nvfree: tail(%lu)={%lu,%lu}\n",
00419               (nvoff_t) ((char *) cur - mem_p), cur->next, cur->size);
00420              slog.p(Logger::Debug) << buf);
00421         if (!i)
00422                 VERB(slog.
00423                      p(Logger::
00424                        Debug) << "NVContainer::nvfree: more than 10000 free blocks!\n");
00425 #else
00426         FreeList *flhead = o2fl(mem_hdr->freelist);
00427         FreeList *cur = NULL, *prv = NULL;
00428 #endif
00429 
00430         pb = o2fl(p - sizeof(unsigned long));
00431         psz = *(unsigned long *) pb;
00432         pe = (FreeList *) ((char *) pb + psz);
00433 
00434 //  ASSERT(memset(pb,255,psz));
00435         ASSERT(if ((char *) pb < mem_p || mem_p + mem_sz < (char *) pe) {
00436                char buf[1024];
00437                close();
00438                sprintf(buf,
00439                        "NVcontainer::nvfree: tried to free illegal memory block ([%p,%p])!\nNVcontainer mapped from [%p,%p]",
00440                        pb, pe, mem_p, mem_p + mem_sz);
00441                throw AssertionError(buf, ERROR_LOCATION);});
00442 
00443         // flhead points to the last free memory block available in the database
00444         prv = flhead;
00445         cur = o2fl(prv->next);
00446         while (cur < pb && cur != flhead) {
00447                 prv = cur;
00448                 cur = o2fl(cur->next);
00449                 ASSERT(if (prv >= cur) {
00450                        throw
00451                        AssertionError
00452                        ("NVContainer::nvfree: freelist out of order!",
00453                         ERROR_LOCATION);}
00454                 );
00455         }
00456         ASSERT(if (cur < pb) {
00457                char buf[1024];
00458                close();
00459                sprintf(buf,
00460                        "NVcontainer::nvfree: tried to free unallocated memory block ([%p,%p])!\n Address must be smaller than flhead (%p)!\nNVcontainer mapped from[%p,%p]",
00461                        pb, pe, flhead, mem_p, mem_p + mem_sz);
00462                throw AssertionError(buf, ERROR_LOCATION);});
00463 
00464         if ((char *) prv + prv->size == (char *) pb) {
00465 #ifdef FREELIST_ASSERT_ON
00466                 VERB(slog.
00467                      p(Logger::Debug) << "NVContainer::nvfree: adjacent to previous\n");
00468 #endif
00469                 // The freed block is adjacent to the previous free block
00470                 prv->size += psz;
00471                 if (pe == cur) {
00472 #ifdef FREELIST_ASSERT_ON
00473                         VERB(slog.
00474                              p(Logger::
00475                                Debug) <<
00476                              "NVContainer::nvfree: adjacent to next---cool\n");
00477 #endif
00478                         // The freed block is adjacent to the next free block too, cool :)
00479                         if (cur == flhead)
00480                                 mem_hdr->freelist = fl2o(prv);
00481                         prv->size += cur->size;
00482                         prv->next = cur->next;
00483                 }
00484         } else if (pe == cur) {
00485 #ifdef FREELIST_ASSERT_ON
00486                 VERB(slog.
00487                      p(Logger::Debug) << "NVContainer::nvfree: adjacent to next\n");
00488 #endif
00489                 // The freed block is adjacent to the next free block
00490                 if (cur->next == fl2o(cur)) {
00491                         // Only one block of free memory left
00492                         ASSERT(if (flhead != cur) {
00493                                throw
00494                                AssertionError
00495                                ("NVContainer::nvfree: flhead lost trailing block of free memory",
00496                                 ERROR_LOCATION);}
00497                         );
00498                         mem_hdr->freelist = pb->next = fl2o(pb);
00499                         pb->size = psz + cur->size;
00500                 } else {
00501                         pb->next = cur->next;
00502                         pb->size = psz + cur->size;
00503                         prv->next = fl2o(pb);
00504                         if (cur == flhead)
00505                                 mem_hdr->freelist = fl2o(pb);
00506                 }
00507         } else {
00508                 VERB(slog.p(Logger::Debug) << "NVContainer::nvfree: not adjacent\n");
00509                 // The freed block neither is adjacent to the previous nor to the 
00510                 // next free block
00511                 pb->next = fl2o(cur);
00512                 pb->size = psz;
00513                 prv->next = fl2o(pb);
00514         }
00515         mem_hdr->bytes_free += psz;
00516 #ifdef FREELIST_ASSERT_ON
00517         i = 10000;
00518         prv = flhead = o2fl(mem_hdr->freelist);;
00519         cur = o2fl(prv->next);
00520 
00521         VERB(sprintf(buf, "NVContainer::nvfree: checking freelist flhead=%p\n", flhead);
00522              slog.p(Logger::Debug) << buf);
00523         while (cur != flhead && i) {
00524                 VERB(sprintf
00525                      (buf, "NVContainer::nvfree: elem(%lu)={%lu,%lu}\n",
00526                       (nvoff_t) ((char *) cur - mem_p), cur->next,
00527                       cur->size); slog.p(Logger::Debug) << buf);
00528                 prv = cur;
00529                 cur = o2fl(cur->next);
00530                 ASSERT(if (prv >= cur) {
00531                        throw
00532                        AssertionError
00533                        ("NVContainer::nvfree: freelist out of order!",
00534                         ERROR_LOCATION);}
00535                 );
00536                 i--;
00537         }
00538         VERB(sprintf
00539              (buf, "NVContainer::nvfree: tail(%lu)={%lu,%lu}\n",
00540               (nvoff_t) ((char *) cur - mem_p), cur->next, cur->size);
00541              slog.p(Logger::Debug) << buf);
00542         if (!i)
00543                 VERB(slog.
00544                      p(Logger::
00545                        Debug) << "NVContainer::nvfree: more than 10000 free blocks!\n");
00546 #endif
00547         lock(UnLock);
00548 }

FreeList* NVcontainer::o2fl nvoff_t  o  )  [inline, private]
 

Definition at line 59 of file NVcontainer.h.

References mem_p.

Referenced by nvalloc(), nvfree(), and resize().

00059                                   {
00060                 return (FreeList *) (o ? mem_p + o : NULL);
00061         }

void NVcontainer::open const char *  dbname,
int  flags = 0
[virtual]
 

Definition at line 611 of file NVcontainer.cc.

References ASSERT, Block, NVcontainer::Header::bytes_free, close(), ERROR_LOCATION, ExclLock, NVcontainer::Header::freelist, NVcontainer::Header::hlen, make_current(), mem_fd, mem_fn, NVcontainer::FreeList::next, nvflock(), NVcontainer::FreeList::size, NVcontainer::Header::size, and UnLock.

Referenced by NVArray::NVArray(), NVcontainer(), NVNewsgroup::NVNewsgroup(), and NVHash::open().

00612 {
00613         ASSERT(if (!dbname) throw
00614                AssertionError
00615                ("NVContainer::open() called with null-pointer\n",
00616                 ERROR_LOCATION));
00617 
00618         if (strcmp(mem_fn, dbname) == 0)
00619                 return;
00620 
00621         if (mem_fd >= 0)
00622                 close();
00623 
00624         struct stat st;
00625 
00626         flags = 0;
00627         strcpy(mem_fn, dbname);
00628         if ((mem_fd =::open(mem_fn, O_RDWR | O_CREAT, 0644)) < 0) {
00629 #ifdef HAVE_SSTREAM
00630                 stringstream sb;
00631 #else
00632                 strstream sb;
00633 #endif
00634                 sb << "NVConatiner::open(): cannot open("
00635                    << " mem_fn: " << ((mem_fn==NULL)? ("NULL") : (mem_fn))
00636                    << ",O_RDWR|O_CREAT)";
00637                 throw SystemError(sb.rdbuf()->str(), errno, ERROR_LOCATION);
00638         }
00639 
00640         nvflock(mem_fd, ExclLock, Block);
00641         if (fstat(mem_fd, &st) < 0) {
00642 #ifdef HAVE_SSTREAM
00643                 stringstream sb;
00644 #else
00645                 strstream sb;
00646 #endif
00647                 sb << "NVConatiner::open(): fstat failed"
00648                    << " mem_fn: " << ((mem_fn==NULL)? ("NULL") : (mem_fn));
00649                 throw SystemError(sb.rdbuf()->str(), errno, ERROR_LOCATION);
00650         }
00651         if (st.st_size == 0) {
00652                 Header hdr;
00653                 FreeList fl;
00654                 hdr.freelist = hdr.hlen;
00655                 hdr.size = 0x10000;
00656                 fl.next = hdr.freelist;
00657                 fl.size = hdr.bytes_free = hdr.size - hdr.hlen;
00658 
00659                 if (ftruncate(mem_fd, hdr.size) < 0) {
00660                         unlink(mem_fn);
00661 #ifdef HAVE_SSTREAM
00662                         stringstream sb;
00663 #else
00664                         strstream sb;
00665 #endif
00666                         sb << "NVConatiner::open(): ftruncate failed, unlinked"
00667                            << " mem_fn: " << ((mem_fn==NULL)? ("NULL") : (mem_fn));
00668                         throw SystemError (sb.rdbuf()->str(), errno, ERROR_LOCATION);
00669                         }
00670                 if (write(mem_fd, &hdr, sizeof(Header)) != sizeof(Header)) {
00671                         unlink(mem_fn);
00672 #ifdef HAVE_SSTREAM
00673                         stringstream sb;
00674 #else
00675                         strstream sb;
00676 #endif
00677                         sb << "NVConatiner::open(): write(info-record) failed, unlinked"
00678                            << " mem_fn: " << ((mem_fn==NULL)? ("NULL") : (mem_fn));
00679                         throw SystemError (sb.rdbuf()->str(), errno, ERROR_LOCATION);
00680                 }
00681                 if (write(mem_fd, &fl, sizeof(FreeList)) !=
00682                     sizeof(FreeList)) {
00683                         unlink(mem_fn);
00684 #ifdef HAVE_SSTREAM
00685                         stringstream sb;
00686 #else
00687                         strstream sb;
00688 #endif
00689                         sb << "NVConatiner::open(): write(free-record) failed unlinked"
00690                            << " mem_fn: " << ((mem_fn==NULL)? ("NULL") : (mem_fn));
00691                         throw SystemError (sb.rdbuf()->str(), errno, ERROR_LOCATION);
00692                 }
00693         }
00694         nvflock(mem_fd, UnLock, Block);
00695 
00696         //Sanity checks of an existing database will be done in 
00697         make_current();
00698 }

void NVcontainer::rename_to_bad_and_close void   ) 
 

Definition at line 724 of file NVcontainer.cc.

References close(), Logger::Error, mem_fn, Logger::p(), and slog.

Referenced by make_current().

00725 {
00726         string f_new = mem_fn;
00727 
00728         f_new += ".bad";
00729         slog.p(Logger::Error) << "NVcontainer::rename_to_bad_and_close: "
00730                 << "Error: bad database file: " << f_new << "\n";
00731         if (rename (mem_fn, f_new.c_str()) != 0) {
00732                 slog.p (Logger::Error) << "NVcontainer::rename_to_bad_and_close: "
00733                         << "rename error: errno=" << errno << " errtxt: "
00734                         << strerror (errno) << "\n";
00735         }
00736         close ();
00737 }

size_t NVcontainer::resize size_t  nsz  )  [protected, virtual]
 

Definition at line 203 of file NVcontainer.cc.

References NVcontainer::Header::bytes_free, ERROR_LOCATION, ExclLock, NVcontainer::Header::freelist, lock(), make_current(), mem_fd, mem_fn, mem_hdr, mem_sz, o2fl(), NVcontainer::Header::size, NVcontainer::FreeList::size, slog, UnLock, and VERB.

Referenced by nvalloc().

00204 {
00205         if (nsz < mem_sz) {
00206                 VERB(slog.
00207                      p(Logger::
00208                        Warning) <<
00209                      "NVContainer: reduction of database size not supported, ignored\n");
00210                 return mem_sz;
00211         }
00212 
00213         lock(ExclLock);
00214         FreeList *flhead = o2fl(mem_hdr->freelist);
00215 
00216         nsz = (nsz + 0x10000) & (~0xffff);
00217         if (ftruncate(mem_fd, nsz) < 0) {
00218 #ifdef HAVE_SSTREAM
00219                 stringstream sb;
00220 #else
00221                 strstream sb;
00222 #endif
00223                 sb << "NVConatiner::resize(): ftruncate failed  "
00224                    << " mem_fn: " << ((mem_fn==NULL)? ("NULL") : (mem_fn))
00225                    << " nsz: " << (unsigned long int) nsz;
00226                 throw SystemError(sb.rdbuf()->str(), errno, ERROR_LOCATION);
00227         }
00228         mem_hdr->bytes_free += nsz - mem_sz;
00229         flhead->size += nsz - mem_sz;
00230         mem_hdr->size = nsz;
00231         make_current();
00232         lock(UnLock);
00233         return mem_sz;
00234 }

void NVcontainer::setdata nvoff_t  d  )  [protected]
 

Definition at line 246 of file NVcontainer.cc.

References mem_hdr, nvoff_t, and NVcontainer::Header::userdata.

Referenced by NVHash::open(), and NVArray::ssetsize().

00247 {
00248         mem_hdr->userdata = d;
00249 }

void NVcontainer::setmtime nvtime_t  tm,
int  force = 0
 

Definition at line 739 of file NVcontainer.cc.

References ExclLock, lock(), mem_hdr, NVcontainer::Header::mtime, nvtime_t, and UnLock.

Referenced by CNewsgroup::prefetchGroup(), NVNewsgroup::readoverdb(), NVActiveDB::setmtime(), CNewsgroup::setsize(), and CNewsgroup::sUpdateOverview().

00740 {
00741         lock(ExclLock);
00742         unsigned long ctm = mem_hdr->mtime;
00743         if (force || tm > ctm)
00744                 mem_hdr->mtime = tm;
00745         lock(UnLock);
00746 }


Member Data Documentation

int NVcontainer::lck_stack[NVcontainer_LOCKSTACKSIZE] [private]
 

Definition at line 52 of file NVcontainer.h.

Referenced by get_lock(), and lock().

int NVcontainer::lck_stackp [private]
 

Definition at line 53 of file NVcontainer.h.

Referenced by close(), get_lock(), lock(), and NVcontainer().

int NVcontainer::mem_fd [private]
 

Definition at line 56 of file NVcontainer.h.

Referenced by close(), is_open(), lock(), make_current(), NVcontainer(), open(), and resize().

char NVcontainer::mem_fn[MAXPATHLEN] [private]
 

Definition at line 55 of file NVcontainer.h.

Referenced by close(), make_current(), NVcontainer(), open(), rename_to_bad_and_close(), and resize().

Header* NVcontainer::mem_hdr [private]
 

Definition at line 57 of file NVcontainer.h.

Referenced by close(), getdata(), getdatap(), getmtime(), is_current(), make_current(), nvalloc(), NVcontainer(), nvfree(), resize(), setdata(), and setmtime().

char* NVcontainer::mem_p [protected]
 

Definition at line 71 of file NVcontainer.h.

Referenced by close(), NVListIter::data(), NVHashIter::data(), fl2o(), NVActiveDB_Iter::get(), getdatap(), make_current(), nvalloc(), NVcontainer(), nvfree(), and o2fl().

size_t NVcontainer::mem_sz [protected]
 

Definition at line 72 of file NVcontainer.h.

Referenced by close(), is_current(), make_current(), nvalloc(), nvfree(), and resize().


The documentation for this class was generated from the following files:
Generated on Sun Oct 24 21:08:24 2004 for NewsCache by doxygen 1.3.6-20040222