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

NVcontainer.cc

Go to the documentation of this file.
00001 #include"NVcontainer.h"
00002 #include"Error.h"
00003 
00004 #include <iostream>
00005 #include<fcntl.h>
00006 #include<stdio.h>
00007 #include<sys/mman.h>
00008 #include<sys/stat.h>
00009 #include<sys/types.h>
00010 #include<time.h>
00011 
00012 #ifdef HAVE_SSTREAM
00013 #include <sstream>
00014 #else
00015 #include <strstream>
00016 #endif
00017 
00018 using namespace std;
00019 
00020 int nvflock(int fd, int cmnd, int block)
00021 {
00022 #ifdef USE_FLOCK
00023         int ncmnd;
00024 
00025         switch (cmnd) {
00026         case NVcontainer::UnLock:
00027                 ncmnd = LOCK_UN;
00028                 break;
00029         case NVcontainer::ShrdLock:
00030                 ncmnd = LOCK_SH;
00031                 break;
00032         case NVcontainer::ExclLock:
00033                 ncmnd = LOCK_EX;
00034                 break;
00035         default:
00036                 DEBUG(cdbg << "myflockerr\n");
00037                 return EINVAL;
00038         }
00039         if (block == NVList::NoBlock)
00040                 ncmnd = ncmnd | LOCK_NB;
00041 
00042         return flock(fd, ncmnd);
00043 #else
00044         int lck;
00045         struct flock ncmnd;
00046         int r;
00047 
00048         switch (cmnd) {
00049         case NVcontainer::UnLock:
00050                 ncmnd.l_type = F_UNLCK;
00051                 break;
00052         case NVcontainer::ShrdLock:
00053                 ncmnd.l_type = F_RDLCK;
00054                 break;
00055         case NVcontainer::ExclLock:
00056                 ncmnd.l_type = F_WRLCK;
00057                 break;
00058         default:
00059                 ASSERT(cerr << "myflockerr\n");
00060                 return EINVAL;
00061         }
00062         ncmnd.l_whence = SEEK_SET;
00063         ncmnd.l_start = 0;
00064         ncmnd.l_len = 0;
00065         if (block == NVcontainer::NoBlock)
00066                 lck = F_SETLK;
00067         else
00068                 lck = F_SETLKW;
00069 
00070         // Unlock, before applying the new lock
00071         if (ncmnd.l_type != F_UNLCK) {
00072                 struct flock ulck;
00073                 ulck.l_type = F_UNLCK;
00074                 ulck.l_whence = SEEK_SET;
00075                 ulck.l_start = 0;
00076                 ulck.l_len = 0;
00077                 if (fcntl(fd, lck, &ulck) < 0)
00078                         return -1;
00079         }
00080         if ((r = fcntl(fd, lck, &ncmnd)) < 0) {
00081                 if (errno == EACCES || errno == EAGAIN)
00082                         errno = EWOULDBLOCK;
00083                 return -1;
00084         }
00085         return 0;
00086 #endif
00087 }
00088 
00089 nvtime_t nvtime(nvtime_t * nvt)
00090 {
00091         time_t tm;
00092         nvtime_t nvtm;
00093 
00094         time(&tm);
00095         nvtm = tm;
00096         if (nvt)
00097                 *nvt = nvtm;
00098 
00099         return nvtm;
00100 }
00101 
00102 NVcontainer::NVcontainer()
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 }
00110 
00111 NVcontainer::NVcontainer(const char *dbname, int flags)
00112 {
00113         lck_stackp = NVcontainer_LOCKSTACKSIZE;
00114         mem_fd = -1;
00115         open(dbname, flags);
00116 }
00117 
00118 NVcontainer::~NVcontainer()
00119 {
00120         close();
00121 }
00122 
00123 void NVcontainer::make_current()
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 }
00202 
00203 size_t NVcontainer::resize(size_t nsz)
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 }
00235 
00236 nvoff_t NVcontainer::getdata()
00237 {
00238         return mem_hdr->userdata;
00239 }
00240 
00241 nvoff_t NVcontainer::getdatap()
00242 {
00243         return ((char *) &mem_hdr->userdata - mem_p);
00244 }
00245 
00246 void NVcontainer::setdata(nvoff_t d)
00247 {
00248         mem_hdr->userdata = d;
00249 }
00250 
00251 nvoff_t NVcontainer::nvalloc(size_t rsz)
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 }
00381 
00382 void NVcontainer::nvfree(nvoff_t p)
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 }
00549 
00550 int NVcontainer::lock(int command, int block)
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 }
00602 
00603 int NVcontainer::get_lock()
00604 {
00605         return lck_stackp <
00606             NVcontainer_LOCKSTACKSIZE ? lck_stack[lck_stackp] : UnLock;
00607 }
00608 
00609 /*
00610  */
00611 void NVcontainer::open(const char *dbname, int flags)
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 }
00699 
00700 int NVcontainer::is_open(void)
00701 {
00702         return mem_fd >= 0;
00703 }
00704 
00705 void NVcontainer::close()
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 }
00723 
00724 void NVcontainer::rename_to_bad_and_close()
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 }
00738         
00739 void NVcontainer::setmtime(nvtime_t tm, int force)
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 }
00747 
00748 void NVcontainer::getmtime(nvtime_t * tm)
00749 {
00750         lock(ShrdLock);
00751         (*tm) = mem_hdr->mtime;
00752         lock(UnLock);
00753 }

Generated on Sun Oct 24 21:08:19 2004 for NewsCache by doxygen 1.3.6-20040222