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 using namespace std;
00013 
00014 int nvflock(int fd, int cmnd, int block)
00015 {
00016 #ifdef USE_FLOCK
00017         int ncmnd;
00018 
00019         switch (cmnd) {
00020         case NVcontainer::UnLock:
00021                 ncmnd = LOCK_UN;
00022                 break;
00023         case NVcontainer::ShrdLock:
00024                 ncmnd = LOCK_SH;
00025                 break;
00026         case NVcontainer::ExclLock:
00027                 ncmnd = LOCK_EX;
00028                 break;
00029         default:
00030                 DEBUG(cdbg << "myflockerr\n");
00031                 return EINVAL;
00032         }
00033         if (block == NVList::NoBlock)
00034                 ncmnd = ncmnd | LOCK_NB;
00035 
00036         return flock(fd, ncmnd);
00037 #else
00038         int lck;
00039         struct flock ncmnd;
00040         int r;
00041 
00042         switch (cmnd) {
00043         case NVcontainer::UnLock:
00044                 ncmnd.l_type = F_UNLCK;
00045                 break;
00046         case NVcontainer::ShrdLock:
00047                 ncmnd.l_type = F_RDLCK;
00048                 break;
00049         case NVcontainer::ExclLock:
00050                 ncmnd.l_type = F_WRLCK;
00051                 break;
00052         default:
00053                 ASSERT(cerr << "myflockerr\n");
00054                 return EINVAL;
00055         }
00056         ncmnd.l_whence = SEEK_SET;
00057         ncmnd.l_start = 0;
00058         ncmnd.l_len = 0;
00059         if (block == NVcontainer::NoBlock)
00060                 lck = F_SETLK;
00061         else
00062                 lck = F_SETLKW;
00063 
00064         // Unlock, before applying the new lock
00065         if (ncmnd.l_type != F_UNLCK) {
00066                 struct flock ulck;
00067                 ulck.l_type = F_UNLCK;
00068                 ulck.l_whence = SEEK_SET;
00069                 ulck.l_start = 0;
00070                 ulck.l_len = 0;
00071                 if (fcntl(fd, lck, &ulck) < 0)
00072                         return -1;
00073         }
00074         if ((r = fcntl(fd, lck, &ncmnd)) < 0) {
00075                 if (errno == EACCES || errno == EAGAIN)
00076                         errno = EWOULDBLOCK;
00077                 return -1;
00078         }
00079         return 0;
00080 #endif
00081 }
00082 
00083 nvtime_t nvtime(nvtime_t * nvt)
00084 {
00085         time_t tm;
00086         nvtime_t nvtm;
00087 
00088         time(&tm);
00089         nvtm = tm;
00090         if (nvt)
00091                 *nvt = nvtm;
00092 
00093         return nvtm;
00094 }
00095 
00096 NVcontainer::NVcontainer()
00097 {
00098         lck_stackp = NVcontainer_LOCKSTACKSIZE;
00099         mem_fn[0] = '\0';
00100         mem_fd = -1;
00101         mem_p = NULL;
00102         mem_hdr = (Header *) mem_p;
00103 }
00104 
00105 NVcontainer::NVcontainer(const char *dbname, int flags)
00106 {
00107         lck_stackp = NVcontainer_LOCKSTACKSIZE;
00108         mem_fd = -1;
00109         open(dbname, flags);
00110 }
00111 
00112 NVcontainer::~NVcontainer()
00113 {
00114         close();
00115 }
00116 
00117 void NVcontainer::make_current()
00118 {
00119         struct stat st;
00120 
00121         if (mem_p) {
00122                 if (is_current())
00123                         return;
00124                 munmap(mem_p, mem_sz);
00125         }
00126 
00127         if (fstat(mem_fd, &st) < 0) {
00128                 throw SystemError("NVContainer(20801): fstat failed",
00129                                   errno, ERROR_LOCATION);
00130         }
00131 
00132         if ((nvoff_t) st.st_size <=
00133             (nvoff_t) sizeof(Header) + (nvoff_t) sizeof(FreeList)) {
00134                 throw Error("NVConatiner(19603): info-record shrunk",
00135                             ERROR_LOCATION);
00136         }
00137 
00138         mem_sz = st.st_size;
00139         mem_p = (char *) mmap(NULL, mem_sz,
00140                               PROT_READ | PROT_WRITE, MAP_SHARED,
00141                               mem_fd, 0);
00142         if (mem_p == (char *) -1) {
00143                 mem_p = NULL;
00144                 throw SystemError("NVContainer(13784): mmap failed", errno,
00145                                   ERROR_LOCATION);
00146         }
00147         mem_hdr = (Header *) mem_p;
00148         //Do some sanity checks on the database
00149         if (mem_hdr->hlen != sizeof(Header) || mem_hdr->version != 2) {
00150                 close();
00151                 throw Error("NVContainer(28196): no nvcontainer",
00152                             ERROR_LOCATION);
00153         }
00154         if (mem_sz != mem_hdr->size) {
00155                 VERB(slog.
00156                      p(Logger::
00157                        Critical) <<
00158                      "NVcontainer: wrong database size stored in db-header - may be a hazard\n");
00159         }
00160 }
00161 
00162 size_t NVcontainer::resize(size_t nsz)
00163 {
00164         if (nsz < mem_sz) {
00165                 VERB(slog.
00166                      p(Logger::
00167                        Warning) <<
00168                      "NVContainer: reduction of database size not supported, ignored\n");
00169                 return mem_sz;
00170         }
00171 
00172         lock(ExclLock);
00173         FreeList *flhead = o2fl(mem_hdr->freelist);
00174 
00175         nsz = (nsz + 0x10000) & (~0xffff);
00176         if (ftruncate(mem_fd, nsz) < 0) {
00177                 throw SystemError("NVList(2756): ftruncate failed", errno,
00178                                   ERROR_LOCATION);
00179         }
00180         mem_hdr->bytes_free += nsz - mem_sz;
00181         flhead->size += nsz - mem_sz;
00182         mem_hdr->size = nsz;
00183         make_current();
00184         lock(UnLock);
00185         return mem_sz;
00186 }
00187 
00188 nvoff_t NVcontainer::getdata()
00189 {
00190         return mem_hdr->userdata;
00191 }
00192 
00193 nvoff_t NVcontainer::getdatap()
00194 {
00195         return ((char *) &mem_hdr->userdata - mem_p);
00196 }
00197 
00198 void NVcontainer::setdata(nvoff_t d)
00199 {
00200         mem_hdr->userdata = d;
00201 }
00202 
00203 nvoff_t NVcontainer::nvalloc(size_t rsz)
00204 {
00205         lock(ExclLock);
00206         FreeList *flhead = o2fl(mem_hdr->freelist);
00207         FreeList *cur, *prv, *res;
00208 
00209         // The allocated memory block has to meet several requirements
00210         // * aligned on 16 Byte boundary
00211         // * size has to be a multiple of 16 (simplifies the alignment)
00212         // * the allocated block has to hold its size
00213         //   the memory after the size indicator will be returned
00214         rsz = (rsz + sizeof(unsigned long) + 0xf) & (~0xf);
00215         if (flhead == NULL) {
00216                 throw
00217                     Error
00218                     ("NVContainer(5946): Database file corrupted (freelist==NULL)",
00219                      ERROR_LOCATION);
00220         }
00221         // flhead points to the last free memory block available in the database
00222         prv = flhead;
00223         cur = o2fl(prv->next);
00224         // find the first suitable memory block in the database
00225         while (cur->size < rsz && cur != flhead) {
00226                 prv = cur;
00227                 cur = o2fl(cur->next);
00228         }
00229 
00230         if (cur == flhead) {
00231                 // Special care has to be taken for the last free memory block
00232                 // It must always be present! So we have to resize it, if its
00233                 // memory is smaller than the requested size plus the size 
00234                 // necessary to maintain the last block of free memory.
00235                 if (flhead->size < rsz + sizeof(FreeList)) {
00236                         nvoff_t prvoff = fl2o(prv);
00237                         // Since it is very likely that the mapped region will change
00238                         // during the resize operation, we will have to save the
00239                         // currently used pointers
00240                         int needsz = rsz + sizeof(FreeList) - flhead->size;
00241                         resize(mem_sz + needsz);
00242                         cur = flhead = o2fl(mem_hdr->freelist);
00243                         prv = o2fl(prvoff);
00244                         ASSERT(if (cur->size < rsz + sizeof(FreeList)) {
00245                                throw
00246                                AssertionError
00247                                ("NVContainer::nvalloc: resize failed",
00248                                 ERROR_LOCATION);}
00249                         );
00250                 }
00251         }
00252         ASSERT(if (cur->size < rsz) {
00253                throw
00254                AssertionError
00255                ("NVContainer::nvalloc: did not find a large enough free memory block",
00256                 ERROR_LOCATION);}
00257         );
00258 
00259         res = cur;
00260 
00261         if (cur->size < rsz + sizeof(FreeList)) {
00262                 // The available space is too small to split?
00263                 // This may only occur if cur _is_not_ the tail of the free blocks
00264                 ASSERT(if (res == flhead) {
00265                        throw
00266                        AssertionError
00267                        ("NVContainer::nvalloc: Cannot split block of free memory at tail of database",
00268                         ERROR_LOCATION);}
00269                 );
00270                 prv->next = cur->next;
00271                 rsz = cur->size;
00272         } else {
00273                 // Split the space into two parts
00274                 cur = (FreeList *) ((char *) cur + rsz);
00275                 cur->size = res->size - rsz;
00276                 if (prv != res) {
00277                         // list contains at least two blocks
00278                         cur->next = res->next;
00279                         prv->next = fl2o(cur);
00280                         if (res == flhead) {
00281                                 mem_hdr->freelist = fl2o(cur);
00282                         }
00283                 } else {
00284                         // list contains only one block pointing to itself
00285                         // this must be the free memory block at the tail
00286                         ASSERT(if (res != flhead) {
00287                                throw
00288                                AssertionError
00289                                ("NVList::nvalloc: Lost block of free memory at tail of database",
00290                                 ERROR_LOCATION);}
00291                         );
00292                         mem_hdr->freelist = cur->next = fl2o(cur);
00293                 }
00294         }
00295         mem_hdr->bytes_free -= rsz;
00296         lock(UnLock);
00297 
00298         *(unsigned long *) res = rsz;
00299 #ifdef FREELIST_ASSERT_ON
00300         char buf[256];
00301         int i = 10000;
00302         prv = flhead = o2fl(mem_hdr->freelist);;
00303         cur = o2fl(prv->next);
00304 
00305         VERB(sprintf
00306              (buf, "nvalloc: checking freelist flhead=%p\n", flhead);
00307              slog.p(Logger::Debug) << buf);
00308         while (cur != flhead && i) {
00309                 VERB(sprintf
00310                      (buf, "nvalloc: elem(%lu)={%lu,%lu}\n",
00311                       (nvoff_t) ((char *) cur - mem_p), cur->next,
00312                       cur->size); slog.p(Logger::Debug) << buf);
00313                 prv = cur;
00314                 cur = o2fl(cur->next);
00315                 ASSERT(if (prv >= cur) {
00316                        throw
00317                        AssertionError
00318                        ("NVContainer::nvalloc: freelist out of order!",
00319                         ERROR_LOCATION);}
00320                 );
00321                 i--;
00322         }
00323         VERB(sprintf
00324              (buf, "nvfree: tail(%lu)={%lu,%lu}\n",
00325               (nvoff_t) ((char *) cur - mem_p), cur->next, cur->size);
00326              slog.p(Logger::Debug) << buf);
00327         if (!i)
00328                 VERB(slog.
00329                      p(Logger::
00330                        Debug) <<
00331                      "nvalloc: more than 10000 free blocks!\n");
00332 #endif
00333         return (nvoff_t) ((char *) res - mem_p) + sizeof(unsigned long);
00334 }
00335 
00336 void NVcontainer::nvfree(nvoff_t p)
00337 {
00338 #ifdef FREELIST_ASSERT_ON
00339         VERB(char buf[256];
00340              sprintf(buf, "NVcontainer::nvfree(%lu)\n", p);
00341              slog.p(Logger::Debug) << buf);
00342 #endif
00343         lock(ExclLock);
00344 
00345         FreeList *pb, *pe;
00346         int psz;
00347 #ifdef FREELIST_ASSERT_ON
00348         FreeList *flhead;
00349         FreeList *cur, *prv;
00350         int i = 10000;
00351         prv = flhead = o2fl(mem_hdr->freelist);;
00352         cur = o2fl(prv->next);
00353 
00354         VERB(sprintf(buf, "nvfree: checking freelist flhead=%p\n", flhead);
00355              slog.p(Logger::Debug) << buf);
00356         while (cur != flhead && i) {
00357                 VERB(sprintf
00358                      (buf, "nvfree: elem(%lu)={%lu,%lu}\n",
00359                       (nvoff_t) ((char *) cur - mem_p), cur->next,
00360                       cur->size); slog.p(Logger::Debug) << buf);
00361                 prv = cur;
00362                 cur = o2fl(cur->next);
00363                 ASSERT(if (prv >= cur) {
00364                        throw
00365                        AssertionError
00366                        ("NVContainer::nvfree: freelist out of order!",
00367                         ERROR_LOCATION);}
00368                 );
00369                 i--;
00370         }
00371         VERB(sprintf
00372              (buf, "nvfree: tail(%lu)={%lu,%lu}\n",
00373               (nvoff_t) ((char *) cur - mem_p), cur->next, cur->size);
00374              slog.p(Logger::Debug) << buf);
00375         if (!i)
00376                 VERB(slog.
00377                      p(Logger::
00378                        Debug) << "nvfree: more than 10000 free blocks!\n");
00379 #else
00380         FreeList *flhead = o2fl(mem_hdr->freelist);
00381         FreeList *cur = NULL, *prv = NULL;
00382 #endif
00383 
00384         pb = o2fl(p - sizeof(unsigned long));
00385         psz = *(unsigned long *) pb;
00386         pe = (FreeList *) ((char *) pb + psz);
00387 
00388 //  ASSERT(memset(pb,255,psz));
00389         ASSERT(if ((char *) pb < mem_p || mem_p + mem_sz < (char *) pe) {
00390                char buf[1024];
00391                close();
00392                sprintf(buf,
00393                        "NVcontainer::nvfree: tried to free illegal memory block ([%p,%p])!\nNVcontainer mapped from [%p,%p]",
00394                        pb, pe, mem_p, mem_p + mem_sz);
00395                throw AssertionError(buf, ERROR_LOCATION);});
00396 
00397         // flhead points to the last free memory block available in the database
00398         prv = flhead;
00399         cur = o2fl(prv->next);
00400         while (cur < pb && cur != flhead) {
00401                 prv = cur;
00402                 cur = o2fl(cur->next);
00403                 ASSERT(if (prv >= cur) {
00404                        throw
00405                        AssertionError
00406                        ("NVContainer::nvfree: freelist out of order!",
00407                         ERROR_LOCATION);}
00408                 );
00409         }
00410         ASSERT(if (cur < pb) {
00411                char buf[1024];
00412                close();
00413                sprintf(buf,
00414                        "NVcontainer::nvfree: tried to free unallocated memory block ([%p,%p])!\n Address must be smaller than flhead (%p)!\nNVcontainer mapped from[%p,%p]",
00415                        pb, pe, flhead, mem_p, mem_p + mem_sz);
00416                throw AssertionError(buf, ERROR_LOCATION);});
00417 
00418         if ((char *) prv + prv->size == (char *) pb) {
00419 #ifdef FREELIST_ASSERT_ON
00420                 VERB(slog.
00421                      p(Logger::Debug) << "nvfree: adjacent to previous\n");
00422 #endif
00423                 // The freed block is adjacent to the previous free block
00424                 prv->size += psz;
00425                 if (pe == cur) {
00426 #ifdef FREELIST_ASSERT_ON
00427                         VERB(slog.
00428                              p(Logger::
00429                                Debug) <<
00430                              "nvfree: adjacent to next---cool\n");
00431 #endif
00432                         // The freed block is adjacent to the next free block too, cool :)
00433                         if (cur == flhead)
00434                                 mem_hdr->freelist = fl2o(prv);
00435                         prv->size += cur->size;
00436                         prv->next = cur->next;
00437                 }
00438         } else if (pe == cur) {
00439 #ifdef FREELIST_ASSERT_ON
00440                 VERB(slog.
00441                      p(Logger::Debug) << "nvfree: adjacent to next\n");
00442 #endif
00443                 // The freed block is adjacent to the next free block
00444                 if (cur->next == fl2o(cur)) {
00445                         // Only one block of free memory left
00446                         ASSERT(if (flhead != cur) {
00447                                throw
00448                                AssertionError
00449                                ("NVContainer::nvfree: flhead lost trailing block of free memory",
00450                                 ERROR_LOCATION);}
00451                         );
00452                         mem_hdr->freelist = pb->next = fl2o(pb);
00453                         pb->size = psz + cur->size;
00454                 } else {
00455                         pb->next = cur->next;
00456                         pb->size = psz + cur->size;
00457                         prv->next = fl2o(pb);
00458                         if (cur == flhead)
00459                                 mem_hdr->freelist = fl2o(pb);
00460                 }
00461         } else {
00462                 VERB(slog.p(Logger::Debug) << "nvfree: not adjacent\n");
00463                 // The freed block neither is adjacent to the previous nor to the 
00464                 // next free block
00465                 pb->next = fl2o(cur);
00466                 pb->size = psz;
00467                 prv->next = fl2o(pb);
00468         }
00469         mem_hdr->bytes_free += psz;
00470 #ifdef FREELIST_ASSERT_ON
00471         i = 10000;
00472         prv = flhead = o2fl(mem_hdr->freelist);;
00473         cur = o2fl(prv->next);
00474 
00475         VERB(sprintf(buf, "nvfree: checking freelist flhead=%p\n", flhead);
00476              slog.p(Logger::Debug) << buf);
00477         while (cur != flhead && i) {
00478                 VERB(sprintf
00479                      (buf, "nvfree: elem(%lu)={%lu,%lu}\n",
00480                       (nvoff_t) ((char *) cur - mem_p), cur->next,
00481                       cur->size); slog.p(Logger::Debug) << buf);
00482                 prv = cur;
00483                 cur = o2fl(cur->next);
00484                 ASSERT(if (prv >= cur) {
00485                        throw
00486                        AssertionError
00487                        ("NVContainer::nvfree: freelist out of order!",
00488                         ERROR_LOCATION);}
00489                 );
00490                 i--;
00491         }
00492         VERB(sprintf
00493              (buf, "nvfree: tail(%lu)={%lu,%lu}\n",
00494               (nvoff_t) ((char *) cur - mem_p), cur->next, cur->size);
00495              slog.p(Logger::Debug) << buf);
00496         if (!i)
00497                 VERB(slog.
00498                      p(Logger::
00499                        Debug) << "nvfree: more than 10000 free blocks!\n");
00500 #endif
00501         lock(UnLock);
00502 }
00503 
00504 int NVcontainer::lock(int command, int block)
00505 {
00506         int res;
00507         int curLock = UnLock;
00508 
00509         if (lck_stackp < NVcontainer_LOCKSTACKSIZE) {
00510                 curLock = lck_stack[lck_stackp];
00511         }
00512         if (command == UnLock) {
00513                 // Unlock container 
00514                 if (lck_stackp >= NVcontainer_LOCKSTACKSIZE) {
00515                         throw
00516                             Error
00517                             ("NVContainer(14364): Lock Stack underflow",
00518                              ERROR_LOCATION);
00519                 }
00520                 lck_stackp++;
00521                 command =
00522                     lck_stackp <
00523                     NVcontainer_LOCKSTACKSIZE ? lck_stack[lck_stackp] :
00524                     UnLock;
00525         } else {
00526                 // Lock container
00527                 if (lck_stackp == 0) {
00528                         throw
00529                             Error
00530                             ("NVContainer(24929): Lock Stack overflow",
00531                              ERROR_LOCATION);
00532                 }
00533                 // Is already locked with excl => new lock must be excl
00534                 if (curLock == ExclLock)
00535                         command = ExclLock;
00536                 lck_stack[--lck_stackp] = command;
00537         }
00538         // Relock if lock state changed
00539         if (curLock != command) {
00540                 if ((res = nvflock(mem_fd, command, block)) < 0) {
00541                         if (errno == EWOULDBLOCK && block == NoBlock) {
00542                                 lck_stackp++;
00543                                 return -1;
00544                         }
00545                         throw
00546                             SystemError("NVContainer(8402): flock failed",
00547                                         errno, ERROR_LOCATION);
00548                 }
00549                 // Adapt to the new size if somebody changed the container's 
00550                 // size
00551                 if (command != UnLock)
00552                         make_current();
00553         }
00554         return 0;
00555 }
00556 
00557 int NVcontainer::get_lock()
00558 {
00559         return lck_stackp <
00560             NVcontainer_LOCKSTACKSIZE ? lck_stack[lck_stackp] : UnLock;
00561 }
00562 
00563 /*
00564  */
00565 void NVcontainer::open(const char *dbname, int flags)
00566 {
00567         ASSERT(if (!dbname) throw
00568                AssertionError
00569                ("NVContainer(1a): open called with null-ointer\n",
00570                 ERROR_LOCATION));
00571 
00572         if (strcmp(mem_fn, dbname) == 0)
00573                 return;
00574 
00575         if (mem_fd >= 0)
00576                 close();
00577 
00578         char errbuf[MAXPATHLEN + 256];
00579         struct stat st;
00580 
00581         flags = 0;
00582         strcpy(mem_fn, dbname);
00583         if ((mem_fd =::open(mem_fn, O_RDWR | O_CREAT, 0644)) < 0) {
00584                 sprintf(errbuf,
00585                         "NVList(15485): Cannot open(%s,O_RDWR|O_CREAT)",
00586                         dbname);
00587                 throw SystemError(errbuf, errno, ERROR_LOCATION);
00588         }
00589 
00590         nvflock(mem_fd, ExclLock, Block);
00591         if (fstat(mem_fd, &st) < 0) {
00592                 throw SystemError("NVContainer(16974): fstat failed",
00593                                   errno, ERROR_LOCATION);
00594         }
00595         if (st.st_size == 0) {
00596                 Header hdr;
00597                 FreeList fl;
00598                 hdr.freelist = hdr.hlen;
00599                 hdr.size = 0x10000;
00600                 fl.next = hdr.freelist;
00601                 fl.size = hdr.bytes_free = hdr.size - hdr.hlen;
00602 
00603                 if (ftruncate(mem_fd, hdr.size) < 0) {
00604                         unlink(mem_fn);
00605                         throw
00606                             SystemError
00607                             ("NVContainer(13947): cannot create nvcontainer",
00608                              errno, ERROR_LOCATION);
00609                 }
00610                 if (write(mem_fd, &hdr, sizeof(Header)) != sizeof(Header)) {
00611                         unlink(mem_fn);
00612                         throw
00613                             SystemError
00614                             ("NVContainer(13948): write(info-record) failed",
00615                              errno, ERROR_LOCATION);
00616                 }
00617                 if (write(mem_fd, &fl, sizeof(FreeList)) !=
00618                     sizeof(FreeList)) {
00619                         unlink(mem_fn);
00620                         throw
00621                             SystemError
00622                             ("NVContainer(23367): write(free-record) failed",
00623                              errno, ERROR_LOCATION);
00624                 }
00625         }
00626         nvflock(mem_fd, UnLock, Block);
00627 
00628         //Sanity checks of an existing database will be done in 
00629         make_current();
00630 }
00631 
00632 int NVcontainer::is_open(void)
00633 {
00634         return mem_fd >= 0;
00635 }
00636 
00637 void NVcontainer::close()
00638 {
00639         if (mem_fd < 0)
00640                 return;
00641         munmap(mem_p, mem_sz);
00642         ::close(mem_fd);
00643         if (lck_stackp != NVcontainer_LOCKSTACKSIZE) {
00644                 VERB(slog.
00645                      p(Logger::
00646                        Critical) <<
00647                      "NVcontainer::close: Forgot to unlock the container before closing it!\n");
00648                 lck_stackp = NVcontainer_LOCKSTACKSIZE;
00649         }
00650         mem_fn[0] = '\0';
00651         mem_fd = -1;
00652         mem_p = NULL;
00653         mem_hdr = (Header *) mem_p;
00654 }
00655 
00656 void NVcontainer::setmtime(nvtime_t tm, int force)
00657 {
00658         lock(ExclLock);
00659         unsigned long ctm = mem_hdr->mtime;
00660         if (force || tm > ctm)
00661                 mem_hdr->mtime = tm;
00662         lock(UnLock);
00663 }
00664 
00665 void NVcontainer::getmtime(nvtime_t * tm)
00666 {
00667         lock(ShrdLock);
00668         (*tm) = mem_hdr->mtime;
00669         lock(UnLock);
00670 }

Generated on Fri Aug 20 10:58:07 2004 for NewsCache by doxygen 1.3.6-20040222