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 #include "CompositeRenumber.h"
00030 #include "SavingLoading.h"
00031 #include "SpaceServerSavable.h"
00032 #include "TimeServerSavable.h"
00033 #include "CoreUtils.h"
00034
00035 #include <fcntl.h>
00036 #include <stdio.h>
00037 #include <stdlib.h>
00038 #include <time.h>
00039
00040 #include <opencog/util/platform.h>
00041
00042 #include <opencog/atomspace/AtomSpaceDefinitions.h>
00043 #include <opencog/atomspace/ClassServer.h>
00044 #include <opencog/atomspace/CompositeTruthValue.h>
00045 #include <opencog/atomspace/HandleIterator.h>
00046 #include <opencog/atomspace/HandleMap.h>
00047 #include <opencog/atomspace/Link.h>
00048 #include <opencog/atomspace/Node.h>
00049 #include <opencog/atomspace/StatisticsMonitor.h>
00050 #include <opencog/atomspace/TLB.h>
00051 #include <opencog/atomspace/types.h>
00052 #include <opencog/util/Logger.h>
00053
00054 using namespace opencog;
00055
00056 #define FULL_NETWORK_DUMP (1 << 0)
00057 #define ATOM_SET (1 << 1)
00058 #define PHYSICAL_ADDRESSING (1 << 2)
00059
00060 #define INDEX_REPORT_FACTOR 1.02
00061 #define POST_PROCESSING_REPORT_FACTOR 1.10
00062
00063 int processed = 0;
00064 int total = 0;
00065
00066 SavingLoading::SavingLoading()
00067 {
00068 }
00069
00070 void SavingLoading::save(const char *fileName, AtomSpace& atomSpace) throw (IOException)
00071 {
00072 logger().info("Starting Memory dump");
00073
00074 time_t start = time(NULL);
00075
00076
00077 FILE *f = fopen(fileName, "wb");
00078 if (f == NULL) {
00079 throw IOException(TRACE_INFO,
00080 "SavingLoading - Unable to open file '%s' for writing", fileName);
00081 }
00082
00083 AtomTable& atomTable = atomSpace.atomTable;
00084
00085
00086 int atomCount = atomTable.getSize();
00087
00088
00089 char format = FULL_NETWORK_DUMP;
00090
00091
00092 fwrite(&format, sizeof(char), 1, f);
00093 fwrite(&atomCount, sizeof(int), 1, f);
00094
00095 processed = 0;
00096 total = atomCount;
00097
00098
00099 saveClassServerInfo(f);
00100
00101 saveNodes(f, atomTable, atomCount);
00102 saveLinks(f, atomTable, atomCount);
00103
00104 TimeServerSavable tss;
00105 tss.setServer(&atomSpace.timeServer);
00106 tss.saveRepository(f);
00107
00108 SpaceServerSavable sss;
00109 sss.setServer(atomSpace.spaceServer);
00110 sss.saveRepository(f);
00111
00112 saveRepositories(f);
00113
00114
00115 fclose(f);
00116
00117
00118 time_t duration = time(NULL) - start;
00119 logger().info("Memory dump: 100%% done (in %d second%c).",
00120 (int) duration, duration == 1 ? '\0' : 's');
00121 fflush(stdout);
00122 }
00123
00124 void SavingLoading::saveClassServerInfo(FILE *f)
00125 {
00126 logger().fine("SavingLoading::saveClassServerInfo");
00127 int numTypes = classserver().getNumberOfClasses();
00128
00129 fwrite(&numTypes, sizeof(int), 1, f);
00130
00131 for (Type i = 0; i < numTypes; i++) {
00132 int classNameLength = classserver().getTypeName(i).length();
00133 fwrite(&classNameLength, sizeof(int), 1, f);
00134 fwrite(classserver().getTypeName(i).c_str(), sizeof(char), classNameLength, f);
00135 fwrite(&i, sizeof(Type), 1, f);
00136 }
00137 }
00138
00139 void SavingLoading::saveNodes(FILE *f, AtomTable& atomTable, int &atomCount)
00140 {
00141 logger().fine("SavingLoading::saveNodes");
00142
00143 int numNodes = 0;
00144
00145
00146 int numNodesOffset = ftell(f);
00147
00148
00149
00150 fwrite(&numNodes, sizeof(int), 1, f);
00151
00152
00153 HandleIterator* iter = atomTable.getHandleIterator(NODE, true);
00154
00155
00156 while (iter->hasNext()) {
00157 Handle atomHandle = iter->next();
00158 Node* node = dynamic_cast<Node*>(TLB::getAtom(atomHandle));
00159 if ( node == NULL ) {
00160 logger().error( "Trying to save a node which isn't registered at TLB. Handle %d", atomHandle.value() );
00161 continue;
00162 }
00163 logger().info( "Saving Node handle %d name %s", atomHandle.value(), node->toString().c_str() );
00164 writeNode(f, node);
00165 numNodes++;
00166 int percentage = (int) (100 * ((float) ++processed / (total * INDEX_REPORT_FACTOR)));
00167 if ((percentage % 10) == 0) {
00168 printf( "Memory dump: %d%% done.\r", percentage);
00169 fflush(stdout);
00170 }
00171 }
00172
00173 delete iter;
00174
00175
00176 fseek(f, numNodesOffset, SEEK_SET);
00177
00178
00179 fwrite(&numNodes, sizeof(int), 1, f);
00180
00181
00182 atomCount -= numNodes;
00183
00184
00185 fseek(f, 0, SEEK_END);
00186 }
00187
00188 void SavingLoading::saveLinks(FILE *f, AtomTable& atomTable, int &atomCount)
00189 {
00190 logger().fine("SavingLoading::saveLinks");
00191
00192 int numLinks = 0;
00193
00194 int numLinksOffset = ftell(f);
00195
00196
00197
00198 fwrite(&numLinks, sizeof(int), 1, f);
00199
00200
00201 HandleIterator* iter = atomTable.getHandleIterator(LINK, true);
00202
00220 std::set<Handle> linkHandles;
00221 while (iter->hasNext()) {
00222 linkHandles.insert( iter->next( ) );
00223 }
00224 delete iter;
00225
00226
00227 std::set<Handle>::iterator itLinks;
00228 for( itLinks = linkHandles.begin( ); itLinks != linkHandles.end( ); ++itLinks ) {
00229 Link* link = dynamic_cast<Link*>(TLB::getAtom(*itLinks));
00230 logger().fine( "Saving Link handle %d name %s", itLinks->value(), link->toString().c_str() );
00231 writeLink(f, link);
00232 numLinks++;
00233 printf( "Memory dump: %d%% done.\r", (int) (100 * ((float) ++processed / (total * INDEX_REPORT_FACTOR))));
00234 fflush(stdout);
00235 }
00236
00237
00238 fseek(f, numLinksOffset, SEEK_SET);
00239
00240
00241 fwrite(&numLinks, sizeof(int), 1, f);
00242
00243
00244 atomCount -= numLinks;
00245
00246
00247 fseek(f, 0, SEEK_END);
00248 }
00249
00250 void SavingLoading::load(const char *fileName, AtomSpace& atomSpace) throw (RuntimeException, IOException, InconsistenceException)
00251 {
00252 clearRepositories();
00253
00254 logger().fine("Starting Memory load");
00255
00256 if (StatisticsMonitor::getInstance()->getAtomCount() > 0) {
00257 throw RuntimeException(TRACE_INFO,
00258 "SavingLoading - Can only load binary image from disk into an empty atom table.");
00259 }
00260
00261 if (atomSpace.getAtomTable().getSize() > 0) {
00262 throw RuntimeException(TRACE_INFO,
00263 "SavingLoading - Can only load binary image from disk in a empty atom table.");
00264 }
00265
00266 time_t start = time(NULL);
00267
00268
00269 FILE *f = fopen(fileName, "rb");
00270 if (f == NULL) {
00271 throw IOException(TRACE_INFO,
00272 "SavingLoading - Unable to open file '%s' for reading.", fileName);
00273 }
00274
00275
00276 char format;
00277 fread(&format, sizeof(char), 1, f);
00278
00279 if (! (format & FULL_NETWORK_DUMP)) {
00280 throw RuntimeException(TRACE_INFO, "SavingLoading - invalid file format '%c'.", format);
00281 }
00282
00283
00284 int atomCount = StatisticsMonitor::getInstance()->getAtomCount();
00285 fread(&atomCount, sizeof(int), 1, f);
00286
00287
00288 HandleMap<Atom *> *handles = new HandleMap<Atom *>();
00289
00290 processed = 0;
00291 total = atomCount;
00292
00293 AtomTable& atomTable = atomSpace.atomTable;
00294
00295 std::vector<Type> dumpToCore;
00296 loadClassServerInfo(f, dumpToCore);
00297 loadNodes(f, handles, atomTable, dumpToCore);
00298 loadLinks(f, handles, atomTable, dumpToCore);
00299
00300 HandleMapIterator<Atom *> *it = handles->keys();
00301 while (it->hasNext()) {
00302 Atom *element = (Atom *)handles->get(it->next());
00303 updateHandles(element, handles);
00304 }
00305 delete(it);
00306
00307 printProgress("load", (int) (100 * (((float) processed + (0.75 * ((total * INDEX_REPORT_FACTOR * POST_PROCESSING_REPORT_FACTOR) - processed))) / (total * INDEX_REPORT_FACTOR * POST_PROCESSING_REPORT_FACTOR))));
00308 fflush(stdout);
00309
00310
00311 TimeServerSavable tss;
00312 tss.setServer(&atomSpace.timeServer);
00313 tss.loadRepository(f, handles);
00314
00315 SpaceServerSavable sss;
00316 sss.setServer(atomSpace.spaceServer);
00317 sss.loadRepository(f, handles);
00318
00319 loadRepositories(f, handles);
00320
00321 delete handles;
00322
00323 fclose(f);
00324
00325
00326 StatisticsMonitor::getInstance()->reevaluateAllStatistics(atomTable);
00327
00328
00329 time_t duration = time(NULL) - start;
00330 logger().info("Memory load: 100%% done (in %d second%c).",
00331 (int) duration, duration == 1 ? '\0' : 's');
00332 fflush(stdout);
00333 }
00334
00335 void SavingLoading::loadClassServerInfo(FILE *f, std::vector<Type>& dumpToCore)
00336 {
00337 logger().fine("SavingLoading::loadClassServerInfo");
00338 char buffer[1 << 16];
00339 int numTypes = classserver().getNumberOfClasses();
00340
00341 int numTypesDump;
00342 fread(&numTypesDump, sizeof(int), 1, f);
00343
00344 dumpToCore.resize(numTypesDump);
00345 for (int i = 0; i < numTypesDump; i++) {
00346 int classNameLength;
00347 fread(&classNameLength, sizeof(int), 1, f);
00348 fread(buffer, sizeof(char), classNameLength, f);
00349 buffer[classNameLength] = '\0';
00350 Type typeDump;
00351 fread(&typeDump, sizeof(Type), 1, f);
00352
00353 if (!classserver().isDefined(buffer)) {
00354 dumpToCore[typeDump] = numTypes + 1;
00355 logger().warn("Warning: type inconsistence found (%d-%s)", typeDump, buffer);
00356 } else {
00357 dumpToCore[typeDump] = classserver().getType(buffer);
00358 }
00359 }
00360
00361 }
00362
00363 void SavingLoading::loadNodes(FILE *f, HandleMap<Atom *> *handles, AtomTable& atomTable, const std::vector<Type>& dumpToCore )
00364 {
00365 logger().fine("SavingLoading::loadNodes");
00366
00367 int numNodes;
00368
00369 fread(&numNodes, sizeof(int), 1, f);
00370
00371
00372 for (int i = 0; i < numNodes; i++) {
00373 Node *node = new Node(NODE, "");
00374
00375 Type oldType;
00376 fread(&oldType, sizeof(Type), 1, f);
00377 if (dumpToCore[oldType] > classserver().getNumberOfClasses()) {
00378 throw InconsistenceException(TRACE_INFO,
00379 "SavingLoading - Type inconsistence clash '%d'.", oldType );
00380 }
00381 node->type = dumpToCore[oldType];
00382 readNode(f, node, handles);
00383
00384 atomTable.add( node );
00385 printProgress("load", (int) (100 * ((float) ++processed / (total * INDEX_REPORT_FACTOR * POST_PROCESSING_REPORT_FACTOR))));
00386 fflush(stdout);
00387 }
00388
00389 }
00390
00391 void SavingLoading::loadLinks(FILE *f, HandleMap<Atom *> *handles, AtomTable& atomTable, const std::vector<Type>& dumpToCore)
00392 {
00393 logger().fine("SavingLoading::loadLinks");
00394
00395 int numLinks;
00396
00397 fread(&numLinks, sizeof(int), 1, f);
00398
00405
00406 for (int i = 0; i < numLinks; i++) {
00407
00408 Link *link = new Link(LINK, std::vector<Handle>());
00409
00410 Type oldType;
00411 fread(&oldType, sizeof(Type), 1, f);
00412 if (dumpToCore[oldType] > classserver().getNumberOfClasses()) {
00413 throw InconsistenceException(TRACE_INFO,
00414 "SavingLoading - Type inconsistence clash '%d'.", oldType );
00415 }
00416 link->type = dumpToCore[oldType];
00417 readLink( f, link, handles );
00418
00419 atomTable.add(link);
00420 }
00421 }
00422
00423 void SavingLoading::updateHandles(Atom *atom, HandleMap<Atom *> *handles)
00424 {
00425 logger().fine("SavingLoading::updateHandles: atom = %p, type = %d", atom, atom->getType());
00426
00427
00428 if (atom->getTruthValue().getType() == COMPOSITE_TRUTH_VALUE) {
00429
00430 CompositeTruthValue ctv((const CompositeTruthValue&) atom->getTruthValue());
00431 CompositeRenumber::updateVersionHandles(ctv, handles);
00432 atom->setTruthValue(ctv);
00433 }
00434
00435
00436 if (classserver().isA(atom->type, LINK)) {
00437 Trail *t = ((Link *)atom)->getTrail();
00438 if (t->getSize()) {
00439
00440 Trail *newTrail = new Trail();
00441 for (size_t i = 0; i < t->getSize(); i++) {
00442 Handle handle = t->getElement(i);
00443 CoreUtils::updateHandle(&handle, handles);
00444 newTrail->insert(handle);
00445 }
00446 ((Link *)atom)->setTrail(newTrail);
00447
00448 delete(t);
00449 }
00450 }
00451
00452 }
00453
00454 void SavingLoading::writeAtom(FILE *f, Atom *atom)
00455 {
00456 logger().info("SavingLoading::writeAtom: %p (type = %d) (handle = %d)", atom, atom->getType(), TLB::getHandle(atom).value( ));
00457
00458
00459 fwrite(&atom->type, sizeof(Type), 1, f);
00460
00461 fwrite(&atom->flags, sizeof(char), 1, f);
00462
00463
00464 Handle handle = TLB::getHandle(atom);
00465 fwrite(&handle, sizeof(Handle), 1, f);
00466
00467
00468
00469
00470 writeAttentionValue(f, atom->getAttentionValue());
00471
00472
00473 writeTruthValue(f, atom->getTruthValue());
00474 }
00475
00476 void SavingLoading::readAtom(FILE *f, HandleMap<Atom *> *handles, Atom *atom)
00477 {
00478 logger().fine("SavingLoading::readAtom()");
00479
00480
00481
00482 fread(&atom->flags, sizeof(char), 1, f);
00483
00484
00485 Handle atomHandle;
00486 fread(&atomHandle, sizeof(Handle), 1, f);
00487
00488 if (handles != NULL) {
00489 handles->add(atomHandle, atom);
00490 logger().fine("Added handles in map: %p => %p (type = %d)", atomHandle.value(), atom, atom->getType());
00491 } else {
00492 logger().warn("No HandleMap while reading atom from file: %p (type = %d)", atom, atom->getType());
00493 }
00494
00495
00496 AttentionValue *av = readAttentionValue(f);
00497 atom->setAttentionValue(*av);
00498 delete (av);
00499
00500 TruthValue *tv = readTruthValue(f);
00501 atom->setTruthValue(*tv);
00502 delete (tv);
00503
00504 }
00505
00506 void SavingLoading::writeNode(FILE *f, Node *node)
00507 {
00508
00509 writeAtom(f, node);
00510
00511
00512 int nameSize = node->name.length();
00513 fwrite(&nameSize, sizeof(int), 1, f);
00514 if (nameSize > 0) {
00515 fwrite(node->name.c_str(), sizeof(char), nameSize, f);
00516 }
00517 }
00518
00519 void SavingLoading::readNode(FILE *f, Node* node, HandleMap<Atom *> *handles)
00520 {
00521 logger().fine("SavingLoading::readNode()");
00522
00523
00524 readAtom(f, handles, node);
00525
00526
00527 int nameSize;
00528 fread(&nameSize, sizeof(int), 1, f);
00529 if (nameSize > 0) {
00530 char *name = new char[nameSize+1];
00531 fread(name, sizeof(char), nameSize, f);
00532 name[nameSize] = '\0';
00533 node->name = name;
00534 delete[](name);
00535 }
00536
00537 }
00538
00539 void SavingLoading::writeLink(FILE *f, Link *link)
00540 {
00541 logger().fine("writeLink(): %s", link->toString().c_str());
00542
00543
00544
00545 writeAtom(f, link);
00546
00547
00548 Arity arity = link->getArity();
00549 fwrite(&arity, sizeof(Arity), 1, f);
00550
00551
00552 for (int i = 0; i < arity; i++) {
00553
00554 fwrite(&(link->outgoing[i]), sizeof(Handle), 1, f);
00555 }
00556
00557
00558 Trail *trail = link->getTrail();
00559
00560 int trailSize = trail->getSize();
00561 fwrite(&trailSize, sizeof(int), 1, f);
00562 for (int i = 0; i < trailSize; i++) {
00563 Handle handle = trail->getElement(i);
00564 fwrite(&handle, sizeof(Handle), 1, f);
00565 }
00566
00567 }
00568
00569 void SavingLoading::writeAttentionValue(FILE *f, const AttentionValue& attentionValue)
00570 {
00571 AttentionValue::sti_t tempSTI = attentionValue.getSTI();
00572 AttentionValue::lti_t tempLTI = attentionValue.getLTI();
00573 AttentionValue::vlti_t tempVLTI = attentionValue.getVLTI();
00574
00575 fwrite(&tempSTI, sizeof(AttentionValue::sti_t), 1, f);
00576 fwrite(&tempLTI, sizeof(AttentionValue::lti_t), 1, f);
00577 fwrite(&tempVLTI, sizeof(AttentionValue::vlti_t), 1, f);
00578 }
00579
00580 void SavingLoading::writeTruthValue(FILE *f, const TruthValue& tv)
00581 {
00582 std::string tvStr = tv.toString();
00583 logger().info( "SavingLoading::writeTruthValue() tvStr = %s\n", tvStr.c_str());
00584 TruthValueType type = tv.getType();
00585 int length = tvStr.size();
00586
00587 fwrite(&type, sizeof(TruthValueType), 1, f);
00588 fwrite(&length, sizeof(int), 1, f);
00589 fwrite(tvStr.c_str(), sizeof(char), length, f);
00590 }
00591
00592 AttentionValue *SavingLoading::readAttentionValue(FILE *f)
00593 {
00594 AttentionValue::sti_t tempSTI;
00595 AttentionValue::lti_t tempLTI;
00596 AttentionValue::vlti_t tempVLTI;
00597
00598 fread(&tempSTI, sizeof(AttentionValue::sti_t), 1, f);
00599 fread(&tempLTI, sizeof(AttentionValue::lti_t), 1, f);
00600 fread(&tempVLTI, sizeof(AttentionValue::vlti_t), 1, f);
00601
00602 return(AttentionValue::factory(tempSTI, tempLTI, tempVLTI));
00603 }
00604
00605
00606 TruthValue *SavingLoading::readTruthValue(FILE *f)
00607 {
00608
00609 TruthValueType type;
00610 int length;
00611
00612 fread(&type, sizeof(TruthValueType), 1, f);
00613 fread(&length, sizeof(int), 1, f);
00614
00615 char *tvStr = new char[length+1];
00616 fread(tvStr, sizeof(char), length, f);
00617 tvStr[length] = '\0';
00618
00619
00620 logger().info("SavingLoading::readTruthValue() tvStr = %s\n", tvStr);
00621 TruthValue* result = TruthValue::factory(type, tvStr);
00622 delete[] tvStr;
00623 return result;
00624 }
00625
00626 void SavingLoading::readLink(FILE *f, Link *link, HandleMap<Atom *> *handles)
00627 {
00628 logger().fine("SavingLoading::readLink()");
00629 readAtom(f, handles, link);
00630
00631
00632 Arity arity;
00633 fread(&arity, sizeof(Arity), 1, f);
00634
00635
00636 for (int i = 0; i < arity; i++) {
00637 Handle h;
00638 fread(&h, sizeof(Handle), 1, f);
00639 link->outgoing.push_back( TLB::getHandle( handles->get(h) ) );
00640 }
00641
00642
00643 Trail *trail = link->getTrail();
00644 int trailSize;
00645 fread(&trailSize, sizeof(int), 1, f);
00646 for (int i = 0; i < trailSize; i++) {
00647 Handle handle;
00648 fread(&handle, sizeof(Handle), 1, f);
00649 trail->insert( handle, false);
00650 }
00651 }
00652
00653 void SavingLoading::printProgress(const char *s, int n)
00654 {
00655 static int old = -1;
00656
00657 if (old != n) {
00658 old = n;
00659 logger().debug("Memory %s: %d%% done.\r", s, n);
00660 }
00661 }
00662
00663 void SavingLoading::addSavableRepository(SavableRepository *repository) throw (RuntimeException)
00664 {
00665 const char* id = repository->getId();
00666
00667 RepositoryHash::const_iterator it = repositories.find(id);
00668 if (it != repositories.end()) {
00669 throw RuntimeException(TRACE_INFO, "SavingLoading - Duplicated repository ids: '%s'.", id);
00670 }
00671
00672 repositories[id] = repository;
00673 }
00674
00675 void SavingLoading::saveRepositories(FILE *f)
00676 {
00677 logger().fine("SavingLoading::saveRepositories");
00678 unsigned int size = repositories.size();
00679 fwrite(&size, sizeof(unsigned int), 1, f);
00680
00681 for (RepositoryHash::const_iterator it = repositories.begin(); it != repositories.end(); it++) {
00682 const std::string& repId = it->first;
00683 int idSize = repId.length() + 1;
00684 fwrite(&idSize, sizeof(int), 1, f);
00685 fwrite(repId.c_str(), sizeof(char), idSize, f);
00686
00687 logger().debug("Saving repository: %s", repId.c_str());
00688 SavableRepository* rep = it->second;
00689 rep->saveRepository(f);
00690
00691 }
00692 }
00693
00694 void SavingLoading::loadRepositories(FILE *f, HandleMap<Atom *> *conv) throw (RuntimeException)
00695 {
00696 logger().fine("SavingLoading::loadRepositories");
00697 unsigned int size;
00698 fread(&size, sizeof(unsigned int), 1, f);
00699
00700 if (size != repositories.size()) {
00701 logger().warn("Number of repositories in dump file (%d) is different from number of registered repositories (%d)", size, repositories.size());
00702 return;
00703 }
00704
00705 for (unsigned int i = 0; i < size; i++) {
00706 int idSize;
00707 fread(&idSize, sizeof(int), 1, f);
00708
00709 std::auto_ptr<char> id(new char[idSize]);
00710
00711 fread(id.get(), sizeof(char), idSize, f);
00712
00713 logger().debug("Loading repository: %s\n", id.get());
00714
00715 RepositoryHash::const_iterator it = repositories.find((const char *)id.get());
00716
00717 if (it == repositories.end()) {
00718 throw RuntimeException(TRACE_INFO,
00719 "SavingLoading - Unknown repository id: '%s'.", id.get());
00720 }
00721
00722
00723 it->second->loadRepository(f, conv);
00724 }
00725
00726 }
00727
00728 void SavingLoading::clearRepositories()
00729 {
00730 logger().fine("SavingLoading::clearRepositories");
00731 for (RepositoryHash::const_iterator it = repositories.begin();
00732 it != repositories.end(); it++) {
00733
00734 it->second->clear();
00735 }
00736 }