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
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
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();
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();
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
00258
00259
00260
00261
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
00268 prv = flhead;
00269 cur = o2fl(prv->next);
00270
00271 while (cur->size < rsz && cur != flhead) {
00272 prv = cur;
00273 cur = o2fl(cur->next);
00274 }
00275
00276 if (cur == flhead) {
00277
00278
00279
00280
00281 if (flhead->size < rsz + sizeof(FreeList)) {
00282 nvoff_t prvoff = fl2o(prv);
00283
00284
00285
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
00309
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
00320 cur = (FreeList *) ((char *) cur + rsz);
00321 cur->size = res->size - rsz;
00322 if (prv != res) {
00323
00324 cur->next = res->next;
00325 prv->next = fl2o(cur);
00326 if (res == flhead) {
00327 mem_hdr->freelist = fl2o(cur);
00328 }
00329 } else {
00330
00331
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
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
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
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
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
00490 if (cur->next == fl2o(cur)) {
00491
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
00510
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
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
00573 if (lck_stackp == 0) {
00574 throw
00575 Error
00576 ("NVContainer::lock(): Lock Stack overflow",
00577 ERROR_LOCATION);
00578 }
00579
00580 if (curLock == ExclLock)
00581 command = ExclLock;
00582 lck_stack[--lck_stackp] = command;
00583 }
00584
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
00596
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
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 }