00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046 #if __linux__
00047 #include <stdint.h>
00048 #endif
00049 #include <stdlib.h>
00050 #include <sys/mman.h>
00051 #include "Basics.H"
00052 #include "VMemPool.H"
00053 #include "VestaSource.H"
00054 #include "VestaConfig.H"
00055 #include "logging.H"
00056 #include "DirShortId.H"
00057 #include "VDirChangeable.H"
00058 #include "VestaAttribsRep.H"
00059 #include "FPShortId.H"
00060 #include <Thread.H>
00061
00062 using std::fstream;
00063 using std::hex;
00064 using std::endl;
00065 using std::streampos;
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084 #define FREEBK_FLAGS 0
00085 #define FREEBK_LENGTH 1
00086 #define FREEBK_NEXT 5
00087 #define FREEBK_MINSIZE 9
00088
00089
00090
00091 class VMemPoolBlockSP : VMemPool {
00092 public:
00093 Bit32 sp;
00094 inline VMemPool::typeCode type() {
00095 return (VMemPool::typeCode)
00096 ((base[sp - 1 + FREEBK_FLAGS] >> 4) & 0xf);
00097 };
00098 inline void setType(VMemPool::typeCode val)
00099 { base[sp - 1 + FREEBK_FLAGS] = ((int) val) << 4; };
00100 inline Bit32 length() {
00101 Bit32 val;
00102 memcpy(&val, &base[sp - 1 + FREEBK_LENGTH], sizeof(Bit32));
00103 return val;
00104 };
00105 inline void setLength(Bit32 val) {
00106 memcpy(&base[sp - 1 + FREEBK_LENGTH], &val, sizeof(Bit32));
00107 };
00108 inline VMemPoolBlockSP next() {
00109 VMemPoolBlockSP val;
00110 memcpy(&val.sp, &base[sp - 1 + FREEBK_NEXT], sizeof(Bit32));
00111 return val;
00112 };
00113 inline void setNext(VMemPoolBlockSP val) {
00114 memcpy(&base[sp - 1 + FREEBK_NEXT], &val.sp, sizeof(Bit32));
00115 };
00116 inline friend int operator==(VMemPoolBlockSP a, VMemPoolBlockSP b)
00117 { return a.sp == b.sp; };
00118 inline friend int operator!=(VMemPoolBlockSP a, VMemPoolBlockSP b)
00119 { return a.sp != b.sp; };
00120 inline VMemPoolBlockSP() { };
00121 inline VMemPoolBlockSP(Bit32 sp) { this->sp = sp; };
00122 };
00123
00124 const VMemPoolBlockSP SNULL(0);
00125
00126
00127 static pthread_once_t once = PTHREAD_ONCE_INIT;
00128 static Basics::mutex mu;
00129 static long page_size;
00130 Bit8* VMemPool::base;
00131 Bit32 VMemPool::totalSize;
00132 Bit32 VMemPool::minGrowBy;
00133 static VMemPoolBlockSP freedMemCursor;
00134 static VMemPoolBlockSP unusedMem;
00135 static VMemPoolBlockSP unusedMemEnd;
00136 static struct {
00137 VMemPool::markCallback markcb;
00138 void* markcl;
00139 VMemPool::sweepCallback sweepcb;
00140 void* sweepcl;
00141 VMemPool::rebuildCallback rebuildcb;
00142 void* rebuildcl;
00143
00144
00145
00146
00147
00148 Bit32 totalSize;
00149 } callback[VMemPool::maxTypeCodes];
00150 static const int CkptMinVersion = 4;
00151 static const int CkptMaxVersion = 11;
00152 static int currentCkptVersion;
00153 int VMemPool::alignmentMask;
00154
00155
00156
00157
00158 static void
00159 setCurrentCkptVersion(int ckptVersion)
00160 {
00161 currentCkptVersion = ckptVersion;
00162 if (ckptVersion >= 7) {
00163
00164
00165
00166
00167 VMemPool::alignmentMask = 7;
00168 } else if (ckptVersion == 6) {
00169 VMemPool::alignmentMask = 3;
00170 } else {
00171 VMemPool::alignmentMask = 0;
00172 }
00173 }
00174
00175 extern "C"
00176 {
00177 void VMemPool_init()
00178 {
00179 VMemPool::init();
00180 }
00181 }
00182
00183 void*
00184 VMemPool::allocate(VMemPool::typeCode type, Bit32 size) throw ()
00185 {
00186 VMemPoolBlockSP p;
00187 Bit32 asize = size;
00188 pthread_once(&once, VMemPool_init);
00189
00190
00191
00192
00193 if (asize < FREEBK_MINSIZE) {
00194 asize = FREEBK_MINSIZE;
00195 }
00196
00197
00198
00199 asize += (-asize) & VMemPool::alignmentMask;
00200 mu.lock();
00201
00202
00203
00204 if (freedMemCursor != SNULL) {
00205 VMemPoolBlockSP prev = freedMemCursor;
00206 p = prev.next();
00207 do {
00208 if (p.length() >= asize) {
00209
00210 Bit32 excess = p.length() - asize;
00211 assert((excess & VMemPool::alignmentMask) == 0);
00212 if (excess < FREEBK_MINSIZE) {
00213
00214 asize = p.length();
00215 if (prev == p) {
00216
00217 freedMemCursor = SNULL;
00218 } else {
00219 prev.setNext(p.next());
00220 freedMemCursor = prev;
00221 }
00222 } else {
00223
00224 VMemPoolBlockSP q;
00225 q.sp = p.sp + asize;
00226 q.setType(VMemPool::freeBlock);
00227 q.setLength(excess);
00228 if (prev == p) {
00229
00230 q.setNext(q);
00231 freedMemCursor = q;
00232 } else {
00233 q.setNext(p.next());
00234 prev.setNext(q);
00235 freedMemCursor = prev;
00236 }
00237 }
00238 goto finish;
00239 }
00240 prev = p;
00241 p = p.next();
00242 } while (prev != freedMemCursor);
00243
00244 }
00245
00246 p = unusedMem;
00247 if (unusedMemEnd.sp - unusedMem.sp <= asize) {
00248
00249 grow(asize - (unusedMemEnd.sp - unusedMem.sp));
00250 }
00251 unusedMem.sp += asize;
00252
00253 finish:
00254 callback[(int)type].totalSize += size;
00255 callback[(int)VMemPool::freeBlock].totalSize -= asize;
00256 while (size < asize) {
00257 ((VMemPoolBlockSP) (p.sp + size++)).setType(VMemPool::freeByte);
00258 callback[(int)VMemPool::freeByte].totalSize++;
00259 }
00260 p.setType(type);
00261 mu.unlock();
00262
00263 void *ret = (void*) VMemPool::lengthenPointer(p.sp);
00264 assert((((PointerInt)ret) & VMemPool::alignmentMask) == 0);
00265
00266 return ret;
00267 }
00268
00269 void
00270 VMemPool::free(void* addr, Bit32 size, typeCode type) throw ()
00271 {
00272 VMemPoolBlockSP p;
00273 p.sp = VMemPool::shortenPointer(addr);
00274 assert((((PointerInt)(addr)) & VMemPool::alignmentMask) == 0);
00275 if (type != unspecified) {
00276 assert(p.type() == type);
00277 }
00278 mu.lock();
00279
00280
00281
00282 if (type != unspecified) {
00283 assert(p.type() == type);
00284 }
00285 callback[(int)p.type()].totalSize -= size;
00286 p.setType(VMemPool::freeBlock);
00287
00288 Bit32 asize = size;
00289 VMemPoolBlockSP q;
00290 q.sp = p.sp + asize;
00291 while (q.sp < unusedMem.sp && q.type() == VMemPool::freeByte) {
00292 q.sp++;
00293 asize++;
00294 callback[(int)VMemPool::freeByte].totalSize--;
00295 }
00296 assert((asize & VMemPool::alignmentMask) == 0);
00297
00298 if (asize < FREEBK_MINSIZE) {
00299
00300
00301 while (size--) {
00302 p.setType(VMemPool::freeByte);
00303 p.sp++;
00304 }
00305 callback[(int)VMemPool::freeByte].totalSize += asize;
00306 } else {
00307 p.setLength(asize);
00308 callback[(int)VMemPool::freeBlock].totalSize += asize;
00309
00310 if (freedMemCursor == SNULL) {
00311 freedMemCursor = p;
00312 p.setNext(p);
00313 } else {
00314 p.setNext(freedMemCursor.next());
00315 freedMemCursor.setNext(p);
00316 }
00317 }
00318 mu.unlock();
00319 }
00320
00321 VMemPool::typeCode
00322 VMemPool::type(void* addr) throw ()
00323 {
00324 VMemPoolBlockSP p;
00325 p.sp = VMemPool::shortenPointer(addr);
00326 return p.type();
00327 }
00328
00329 void
00330 VMemPool::gc(ShortId keepDerivedSid) throw ()
00331 {
00332 int i;
00333 pthread_once(&once, VMemPool_init);
00334 mu.lock();
00335
00336
00337 for (i = 0; i < (int) VMemPool::maxTypeCodes; i++) {
00338 if (callback[i].markcb != NULL) {
00339 callback[i].markcb(callback[i].markcl,
00340 (VMemPool::typeCode) i);
00341 }
00342 callback[i].totalSize = 0;
00343 }
00344
00345
00346
00347
00348
00349 if (keepDerivedSid != NullShortId) {
00350 SourceOrDerived sidstream;
00351 sidstream.open(keepDerivedSid);
00352 sidstream >> hex;
00353 for (;;) {
00354 ShortId nextkeep;
00355 sidstream >> nextkeep;
00356 if (sidstream.fail()) {
00357 assert(sidstream.eof());
00358 break;
00359 }
00360 if (SourceOrDerived::dirShortId(nextkeep)) {
00361 Bit32 sp = GetDirShortId(nextkeep);
00362 if (sp != 0) {
00363 VDirChangeable vs(VestaSource::immutableDirectory,
00364 (Bit8*) VMemPool::lengthenPointer(sp));
00365 if (!vs.hasName()) {
00366 vs.setHasName(true);
00367 vs.mark();
00368 }
00369 }
00370 }
00371 }
00372 sidstream.close();
00373 }
00374
00375
00376
00377 VMemPoolBlockSP p;
00378 p.sp = VMemPool::shortenPointer(base);
00379 VMemPoolBlockSP curFree;
00380 curFree = SNULL;
00381 Bit32 curFreeSize = 0;
00382 freedMemCursor = SNULL;
00383 while (p.sp < unusedMem.sp) {
00384 VMemPool::typeCode ptype = p.type();
00385 Bit32 size;
00386 bool free =
00387 !callback[(int) ptype].sweepcb(callback[(int) ptype].sweepcl,
00388 ptype, (void*)
00389 VMemPool::lengthenPointer(p.sp),
00390 size);
00391 if (free) {
00392
00393
00394 if (curFree == SNULL) {
00395 curFree = p;
00396 curFreeSize = size;
00397 } else {
00398 curFreeSize += size;
00399 }
00400 } else {
00401 if (curFree != SNULL) {
00402
00403 while ((curFree.sp - 1) & VMemPool::alignmentMask) {
00404 callback[(int)VMemPool::freeByte].totalSize++;
00405 curFree.setType(VMemPool::freeByte);
00406 curFree.sp++;
00407 curFreeSize--;
00408 }
00409 assert((curFreeSize & VMemPool::alignmentMask) == 0);
00410 if (curFreeSize < FREEBK_MINSIZE) {
00411 callback[(int)VMemPool::freeByte].totalSize +=curFreeSize;
00412 while (curFreeSize--) {
00413 curFree.setType(VMemPool::freeByte);
00414 curFree.sp++;
00415 }
00416 } else {
00417 callback[(int)VMemPool::freeBlock].totalSize +=curFreeSize;
00418 curFree.setType(VMemPool::freeBlock);
00419 curFree.setLength(curFreeSize);
00420 if (freedMemCursor == SNULL) {
00421 freedMemCursor = curFree;
00422 curFree.setNext(curFree);
00423 } else {
00424 curFree.setNext(freedMemCursor.next());
00425 freedMemCursor.setNext(curFree);
00426 }
00427 }
00428 curFree = SNULL;
00429 curFreeSize = 0;
00430 }
00431 callback[(int) ptype].totalSize += size;
00432 }
00433 p.sp += size;
00434 assert(p.sp <= unusedMem.sp);
00435 }
00436
00437 if (curFree != SNULL) {
00438
00439 while ((curFree.sp - 1) & VMemPool::alignmentMask) {
00440 assert(curFree.sp < unusedMemEnd.sp);
00441 callback[(int)VMemPool::freeByte].totalSize++;
00442 curFree.setType(VMemPool::freeByte);
00443 curFree.sp++;
00444 curFreeSize--;
00445 }
00446 unusedMem = curFree;
00447 }
00448
00449
00450 LogAllDirShortIds("fsid");
00451
00452
00453 VMemPool::rebuildDirShortIdTable();
00454
00455 if (Repos::isDebugLevel(DBG_VMEMPOOL)) {
00456 Repos::dprintf(0, "Memory pool size statistics:\n"
00457 "freeByte\t%u\n"
00458 "freeBlock\t%u\n"
00459 "vDirChangeable\t%u\n"
00460 "vForward\t%u\n"
00461 "vDirEvaluator\t%u\n"
00462 "vDirImmutable\t%u\n"
00463 "vAttrib\t\t%u\n"
00464 "vDirAppendable\t%u\n",
00465 callback[freeByte].totalSize,
00466 callback[freeBlock].totalSize,
00467 callback[vDirChangeable].totalSize,
00468 callback[vForward].totalSize,
00469 callback[vDirEvaluator].totalSize,
00470 callback[vDirImmutable].totalSize,
00471 callback[vAttrib].totalSize,
00472 callback[vDirAppendable].totalSize);
00473 VDirChangeable::printStats();
00474 }
00475
00476 mu.unlock();
00477 }
00478
00479
00480 void
00481 VMemPool::rebuildDirShortIdTable() throw ()
00482 {
00483 DeleteAllDirShortIds();
00484 DeleteAllFPShortId();
00485
00486
00487
00488 VMemPoolBlockSP p;
00489 p.sp = VMemPool::shortenPointer(base);
00490 while (p.sp < unusedMem.sp) {
00491 VMemPool::typeCode ptype = p.type();
00492 Bit32 size = 0, oldsize;
00493 oldsize = size;
00494 callback[(int) ptype].rebuildcb(callback[(int) ptype].rebuildcl,
00495 ptype, (void*)
00496 VMemPool::lengthenPointer(p.sp),
00497 size);
00498 assert(size > 0);
00499 p.sp += size;
00500 assert(p.sp <= unusedMem.sp);
00501 }
00502 }
00503
00504 void
00505 VMemPool::registerCallbacks(VMemPool::typeCode type,
00506 VMemPool::markCallback markcb, void* markcl,
00507 VMemPool::sweepCallback sweepcb, void* sweepcl,
00508 VMemPool::rebuildCallback rebuildcb,
00509 void* rebuildcl) throw ()
00510 {
00511 pthread_once(&once, VMemPool_init);
00512 mu.lock();
00513 callback[(int) type].markcb = markcb;
00514 callback[(int) type].markcl = markcl;
00515 callback[(int) type].sweepcb = sweepcb;
00516 callback[(int) type].sweepcl = sweepcl;
00517 callback[(int) type].rebuildcb = rebuildcb;
00518 callback[(int) type].rebuildcl = rebuildcl;
00519 callback[(int) type].totalSize = 0;
00520 mu.unlock();
00521 }
00522
00523
00524 static bool sweepFreeByteCallback(void* closure, VMemPool::typeCode type,
00525 void* addr, Bit32& size)
00526 {
00527 size = 1;
00528 return false;
00529 }
00530
00531 static void rebuildFreeByteCallback(void* closure, VMemPool::typeCode type,
00532 void* addr, Bit32& size)
00533 {
00534 size = 1;
00535 }
00536
00537 static bool sweepFreeBlockCallback(void* closure, VMemPool::typeCode type,
00538 void* addr, Bit32& size)
00539 {
00540 size = ((VMemPoolBlockSP) VMemPool::shortenPointer(addr)).length();
00541 return false;
00542 }
00543
00544 static void rebuildFreeBlockCallback(void* closure, VMemPool::typeCode type,
00545 void* addr, Bit32& size)
00546 {
00547 size = ((VMemPoolBlockSP) VMemPool::shortenPointer(addr)).length();
00548 }
00549
00550 void
00551 VMemPool::init()
00552 {
00553 page_size = sysconf(_SC_PAGE_SIZE);
00554 setCurrentCkptVersion(CkptMaxVersion);
00555 mu.lock();
00556 Bit8* baseReq;
00557 try {
00558 Text t;
00559 if (VestaConfig::get("Repository", "VMemPool_size", t)) {
00560
00561
00562 errno = 0;
00563 totalSize = strtoul(t.cchars(), NULL, 0);
00564 if(errno == ERANGE)
00565 {
00566 Repos::dprintf(DBG_ALWAYS,
00567 "Fatal: [Repository]VMemPool_size is too large\n");
00568 abort();
00569 }
00570 assert(totalSize > 0);
00571 totalSize = (((totalSize - 1) / page_size) + 1) * page_size;
00572 } else {
00573 totalSize = page_size;
00574 }
00575 if (VestaConfig::get("Repository", "VMemPool_base", t)) {
00576
00577
00578 errno = 0;
00579 baseReq = (Bit8*) strtoul(t.cchars(), NULL, 0);
00580 if(errno == ERANGE)
00581 {
00582 Repos::dprintf(DBG_ALWAYS,
00583 "Fatal: [Repository]VMemPool_base is too large\n");
00584 abort();
00585 }
00586 baseReq = (Bit8*) (((((PointerInt) baseReq - 1)
00587 / page_size) + 1) * page_size);
00588 } else {
00589 baseReq = NULL;
00590 }
00591 if (VestaConfig::get("Repository", "VMemPool_minGrowBy", t)) {
00592
00593
00594 errno = 0;
00595 minGrowBy = (Bit32) strtoul(t.cchars(), NULL, 0);
00596 if(errno == ERANGE)
00597 {
00598 Repos::dprintf(DBG_ALWAYS,
00599 "Fatal: [Repository]VMemPool_minGrowBy is too large\n");
00600 abort();
00601 }
00602 } else {
00603 minGrowBy = page_size;
00604 }
00605 } catch (VestaConfig::failure f) {
00606 Repos::dprintf(DBG_ALWAYS, "VMemPool::init got VestaConfig::failure: %s\n",
00607 f.msg.cchars());
00608 abort();
00609 }
00610 #if MALLOC_VMEMPOOL
00611 base = (Bit8*) malloc(totalSize);
00612 assert(base != NULL);
00613 #else
00614 if (baseReq == NULL) {
00615 base = (Bit8*) mmap(baseReq, totalSize, PROT_READ|PROT_WRITE,
00616 MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
00617 } else {
00618 base = (Bit8*) mmap(baseReq, totalSize, PROT_READ|PROT_WRITE,
00619 MAP_ANONYMOUS|MAP_FIXED|MAP_PRIVATE, -1, 0);
00620 }
00621 assert(base != (Bit8*) -1);
00622 #endif
00623 unusedMemEnd.sp = totalSize;
00624 freedMemCursor = SNULL;
00625 unusedMem.sp = VMemPool::shortenPointer(base);
00626 callback[(int) VMemPool::freeByte].sweepcb = sweepFreeByteCallback;
00627 callback[(int) VMemPool::freeByte].rebuildcb = rebuildFreeByteCallback;
00628 callback[(int) VMemPool::freeByte].totalSize = 0;
00629 callback[(int) VMemPool::freeBlock].sweepcb = sweepFreeBlockCallback;
00630 callback[(int) VMemPool::freeBlock].rebuildcb = rebuildFreeBlockCallback;
00631 callback[(int) VMemPool::freeBlock].totalSize = totalSize;
00632 Repos::dprintf(DBG_VMEMPOOL, "VMemPool baseReq 0x%p, base 0x%p,\n"
00633 " size 0x%x, minGrowBy 0x%x\n",
00634 baseReq, base, totalSize, minGrowBy);
00635 mu.unlock();
00636 }
00637
00638 void
00639 VMemPool::grow(Bit32 growBy) throw ()
00640 {
00641 #if NOGROW_VMEMPOOL
00642 Repos::dprintf(DBG_ALWAYS,
00643 "Out of memory; crashing! (total %d, used %d, req %d)\n",
00644 unusedMemEnd.sp, unusedMem.sp, growBy);
00645 abort();
00646 #else
00647 Bit32 gb = growBy;
00648 if (gb < minGrowBy) gb = minGrowBy;
00649 #if MALLOC_VMEMPOOL
00650
00651 base = (Bit8*) realloc(base, totalSize + gb);
00652 assert(base != NULL);
00653 #else
00654 gb = (((gb - 1) / page_size) + 1) * page_size;
00655 void* more = mmap(base + totalSize, gb, PROT_READ|PROT_WRITE,
00656 MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
00657 assert(more == base + totalSize);
00658 #endif
00659 totalSize += gb;
00660 callback[(int)VMemPool::freeBlock].totalSize += gb;
00661 Repos::dprintf(DBG_VMEMPOOL,
00662 "VMemPool grow req 0x%x, rounded 0x%x, new size 0x%x\n",
00663 growBy, gb, totalSize);
00664 unusedMemEnd.sp = totalSize;
00665 #endif
00666 }
00667
00668
00669
00670
00671
00672 void
00673 VMemPool::writeCheckpoint(fstream& ckpt) throw ()
00674 {
00675 Bit32 nextSP = 1;
00676 Bit32 endianFlag = 0x01020304;
00677
00678 mu.lock();
00679
00680
00681
00682
00683 VestaSource* rr = VestaSource::repositoryRoot();
00684 VestaSource* mr = VestaSource::mutableRoot();
00685 VestaSource* vr = VestaSource::volatileRoot();
00686
00687
00688 setCurrentCkptVersion(CkptMaxVersion);
00689 ckpt << "(smem " << CkptMaxVersion << endl;
00690 ckpt.write((char *) &endianFlag, sizeof(Bit32));
00691
00692
00693 streampos lenpos = ckpt.tellp();
00694 ckpt.write((char *) &nextSP, sizeof(Bit32));
00695
00696
00697 Bit32 rSP = rr->checkpoint(nextSP, ckpt);
00698 Bit32 mSP = mr->checkpoint(nextSP, ckpt);
00699 CheckpointAllDirShortIds(nextSP, ckpt);
00700
00701
00702 VestaAttribsRep* ar;
00703 ar = (VestaAttribsRep*) VMemPool::lengthenPointer(rr->firstAttrib());
00704 Bit32 raSP = 0;
00705 if (ar) raSP = ar->checkpoint(nextSP, ckpt);
00706 rr->rep = NULL;
00707 *(Bit32*)rr->attribs = 0;
00708 ar = (VestaAttribsRep*) VMemPool::lengthenPointer(mr->firstAttrib());
00709 Bit32 maSP = 0;
00710 if (ar) maSP = ar->checkpoint(nextSP, ckpt);
00711 mr->rep = NULL;
00712 *(Bit32*)mr->attribs = 0;
00713
00714
00715 streampos endpos = ckpt.tellp();
00716 ckpt.seekp(lenpos, fstream::beg);
00717 ckpt.write((char *) &nextSP, sizeof(Bit32));
00718 ckpt.seekp(endpos, fstream::beg);
00719 ckpt << "\n)\n";
00720
00721
00722 ckpt << "(rroot " << rSP << " " << raSP << ")\n";
00723 ckpt << "(mroot " << mSP << " " << maSP << ")\n";
00724
00725
00726 ckpt << "(vmem " << CkptMaxVersion << endl;
00727 ckpt.write((char *) &endianFlag, sizeof(Bit32));
00728
00729
00730 lenpos = ckpt.tellp();
00731 ckpt.write((char *) &nextSP, sizeof(Bit32));
00732
00733 (void) vr->checkpoint(nextSP, ckpt);
00734
00735
00736 ar = (VestaAttribsRep*) VMemPool::lengthenPointer(vr->firstAttrib());
00737 Bit32 vaSP = 0;
00738 if (ar) vaSP = ar->checkpoint(nextSP, ckpt);
00739 *(Bit32*)vr->attribs = 0;
00740
00741
00742 endpos = ckpt.tellp();
00743 ckpt.seekp(lenpos, fstream::beg);
00744 ckpt.write((char *) &nextSP, sizeof(Bit32));
00745 ckpt.seekp(endpos, fstream::beg);
00746 ckpt << "\n)\n";
00747
00748
00749 ckpt << "(vroot " << vaSP << ")\n";
00750
00751 mu.unlock();
00752 }
00753
00754 static void assertGood(fstream& ckpt)
00755 {
00756 if (!ckpt.good()) {
00757 Repos::dprintf(DBG_ALWAYS,
00758 "read from checkpoint file failed: errno %d\n", errno);
00759 assert(ckpt.good());
00760 }
00761 }
00762
00763 void
00764 VMemPool::readCheckpoint(fstream& ckpt, bool readVolatile) throw ()
00765 {
00766 char buf1[64];
00767 char buf2[64];
00768 char newline;
00769 Bit32 endianFlag;
00770 Bit32 nextSP, rootSP, rootAttribsSP;
00771 int ckptVersion;
00772
00773 mu.lock();
00774
00775
00776 VestaSource* rr = VestaSource::repositoryRoot();
00777 VestaSource* mr = VestaSource::mutableRoot();
00778 VestaSource* vr = VestaSource::volatileRoot();
00779
00780
00781 ckpt.get(buf1, sizeof(buf1));
00782 assertGood(ckpt);
00783 int ok = sscanf(buf1, "(smem %d", &ckptVersion);
00784 assert(ok == 1);
00785 if (ckptVersion < CkptMinVersion || ckptVersion > CkptMaxVersion) {
00786 Repos::dprintf(DBG_ALWAYS, "checkpoint version %d not between %d and %d\n",
00787 ckptVersion, CkptMinVersion, CkptMaxVersion);
00788 exit(2);
00789 }
00790 setCurrentCkptVersion(ckptVersion);
00791 ckpt.get(newline);
00792 assertGood(ckpt);
00793 assert(newline == '\n');
00794 ckpt.read((char *) &endianFlag, sizeof(Bit32));
00795 assertGood(ckpt);
00796 switch (endianFlag) {
00797 case 0x01020304:
00798 break;
00799 case 0x04030201:
00800 assert(false);
00801 break;
00802 default:
00803 assert(false);
00804 break;
00805 }
00806 ckpt.read((char *) &nextSP, sizeof(Bit32));
00807 assertGood(ckpt);
00808
00809
00810 if (nextSP > unusedMemEnd.sp) {
00811 grow(nextSP - unusedMemEnd.sp);
00812 }
00813 ckpt.read((char *) VMemPool::base, nextSP - 1);
00814 assertGood(ckpt);
00815 freedMemCursor = SNULL;
00816 Bit32 volSP = nextSP;
00817 assert(((nextSP - 1) & VMemPool::alignmentMask) == 0);
00818 unusedMem.sp = nextSP;
00819
00820
00821 ckpt.get(newline);
00822 assertGood(ckpt);
00823 assert(newline == '\n');
00824 ckpt.get(buf2, sizeof(buf2));
00825 assertGood(ckpt);
00826 assert(strcmp(buf2, ")") == 0);
00827 ckpt.get(newline);
00828 assertGood(ckpt);
00829 assert(newline == '\n');
00830
00831
00832 if (ckptVersion >= 5) {
00833 ckpt >> buf1 >> rootSP >> rootAttribsSP >> buf2;
00834 } else {
00835 ckpt >> buf1 >> rootSP >> buf2;
00836 rootAttribsSP = 0;
00837 }
00838 assertGood(ckpt);
00839 assert(strcmp(buf1, "(rroot") == 0);
00840 assert(strcmp(buf2, ")") == 0);
00841 ckpt.get(newline);
00842 assertGood(ckpt);
00843 assert(newline == '\n');
00844 rr->rep = (Bit8*) VMemPool::lengthenPointer(rootSP);
00845 *(Bit32*) rr->attribs = rootAttribsSP;
00846 rr->resync();
00847
00848 if (ckptVersion >= 5) {
00849 ckpt >> buf1 >> rootSP >> rootAttribsSP >> buf2;
00850 } else {
00851 ckpt >> buf1 >> rootSP >> buf2;
00852 rootAttribsSP = 0;
00853 }
00854 assertGood(ckpt);
00855 assert(strcmp(buf1, "(mroot") == 0);
00856 assert(strcmp(buf2, ")") == 0);
00857 ckpt.get(newline);
00858 assertGood(ckpt);
00859 assert(newline == '\n');
00860 mr->rep = (Bit8*) VMemPool::lengthenPointer(rootSP);
00861 *(Bit32*) mr->attribs = rootAttribsSP;
00862 mr->resync();
00863
00864
00865 ckpt.get(buf1, sizeof(buf1));
00866 assertGood(ckpt);
00867 ok = sscanf(buf1, "(vmem %d", &ckptVersion);
00868 assert(ok == 1);
00869
00870 ckpt.get(newline);
00871 assertGood(ckpt);
00872 assert(newline == '\n');
00873 ckpt.read((char *) &endianFlag, sizeof(Bit32));
00874 assertGood(ckpt);
00875 switch (endianFlag) {
00876 case 0x01020304:
00877 break;
00878 case 0x04030201:
00879 assert(false);
00880 break;
00881 default:
00882 assert(false);
00883 break;
00884 }
00885 ckpt.read((char *) &nextSP, sizeof(Bit32));
00886 assertGood(ckpt);
00887
00888
00889 if (readVolatile) {
00890
00891
00892 assert(ckptVersion == CkptMaxVersion);
00893 assert(nextSP >= unusedMem.sp);
00894
00895 if (nextSP > unusedMemEnd.sp) {
00896 grow(nextSP - unusedMemEnd.sp);
00897 }
00898 #if 0
00899
00900
00901 ckpt.read((char *) VMemPool::lengthenPointer(unusedMem.sp),
00902 nextSP - unusedMem.sp);
00903 #else
00904 if (nextSP > unusedMem.sp) {
00905 ckpt.read((char *) VMemPool::lengthenPointer(unusedMem.sp),
00906 nextSP - unusedMem.sp);
00907 assertGood(ckpt);
00908 }
00909 #endif
00910 unusedMem.sp = nextSP;
00911 } else {
00912
00913 ckpt.seekg(nextSP - volSP, std::ios::cur);
00914 assertGood(ckpt);
00915 }
00916
00917
00918 ckpt.get(newline);
00919 assertGood(ckpt);
00920 assert(newline == '\n');
00921 ckpt.get(buf2, sizeof(buf2));
00922 assertGood(ckpt);
00923 assert(strcmp(buf2, ")") == 0);
00924 ckpt.get(newline);
00925 assertGood(ckpt);
00926 assert(newline == '\n');
00927
00928
00929 if (ckptVersion >= 11) {
00930 ckpt >> buf1 >> rootAttribsSP >> buf2;
00931 assertGood(ckpt);
00932 assert(strcmp(buf1, "(vroot") == 0);
00933 assert(strcmp(buf2, ")") == 0);
00934 if (readVolatile) {
00935 *(Bit32*) vr->attribs = rootAttribsSP;
00936 vr->resync();
00937 }
00938 }
00939
00940 rebuildDirShortIdTable();
00941
00942 mu.unlock();
00943 }
00944