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
00036 #include "OW_config.h"
00037 #include "OW_HDB.hpp"
00038 #include "OW_AutoPtr.hpp"
00039 #include "OW_Format.hpp"
00040 #if defined(OW_HAVE_ISTREAM) && defined(OW_HAVE_OSTREAM)
00041 #include <istream>
00042 #include <ostream>
00043 #else
00044 #include <iostream>
00045 #endif
00046 #include <cstring>
00047
00048 extern "C"
00049 {
00050 #include <errno.h>
00051 }
00052
00053 namespace OW_NAMESPACE
00054 {
00055
00056 static UInt32 calcCheckSum(unsigned char* src, Int32 len);
00058 HDB::HDB() :
00059 m_hdrBlock(), m_fileName(), m_version(0), m_hdlCount(0),
00060 m_opened(false), m_pindex(NULL), m_indexGuard(), m_guard()
00061 {
00062 }
00064 HDB::~HDB()
00065 {
00066 try
00067 {
00068 if (m_hdlCount > 0)
00069 {
00070
00071 }
00072 close();
00073 }
00074 catch (...)
00075 {
00076
00077 }
00078 }
00080 void
00081 HDB::close()
00082 {
00083 if (m_opened)
00084 {
00085 m_pindex->close();
00086 m_pindex = 0;
00087 m_opened = false;
00088 m_lockFile.unlock();
00089 m_lockFile.close();
00090 }
00091 }
00093 void
00094 HDB::open(const char* fileName)
00095 {
00096 MutexLock l(m_guard);
00097 if (m_opened)
00098 {
00099 return;
00100 }
00101 m_hdlCount = 0;
00102 m_version = 0;
00103 m_fileName = fileName;
00104
00105 String lockFilename = m_fileName + ".lock";
00106 m_lockFile = FileSystem::openOrCreateFile(lockFilename);
00107 if (!m_lockFile)
00108 {
00109 OW_THROW(HDBException,
00110 Format("Unable to open or create lock: %1, errno: %2(%3)",
00111 lockFilename, errno, strerror(errno)).c_str());
00112 }
00113
00114
00115 if (m_lockFile.tryLock() == -1)
00116 {
00117 OW_THROW(HDBException,
00118 Format("Unable to lock HDB, verify it's not in use: %1, errno: %2(%3)",
00119 lockFilename, errno, strerror(errno)).c_str());
00120 }
00121
00122 String fname = m_fileName + ".dat";
00123 createFile();
00124 checkFile();
00125 m_fileName = fname;
00126 m_opened = true;
00127 }
00129 bool
00130 HDB::createFile()
00131 {
00132 HDBHeaderBlock b = { OW_HDBSIGNATURE, HDBVERSION, -1L, -1L, -1L };
00133 m_hdrBlock = b;
00134 File f = FileSystem::createFile(m_fileName + ".dat");
00135 if (!f)
00136 {
00137 return false;
00138 }
00139 if (f.write(&m_hdrBlock, sizeof(m_hdrBlock), 0) != sizeof(m_hdrBlock))
00140 {
00141 f.close();
00142 OW_THROW(HDBException, "Failed to write header of HDB");
00143 }
00144 f.close();
00145
00146 m_pindex = Index::createIndexObject();
00147 m_pindex->open(m_fileName.c_str());
00148 return true;
00149 }
00151 void
00152 HDB::checkFile()
00153 {
00154 File f = FileSystem::openFile(m_fileName + ".dat");
00155 if (!f)
00156 {
00157 String msg("Failed to open file: ");
00158 msg += m_fileName;
00159 OW_THROW(HDBException, msg.c_str());
00160 }
00161 if (f.read(&m_hdrBlock, sizeof(m_hdrBlock), 0) != sizeof(m_hdrBlock))
00162 {
00163 f.close();
00164 String msg("Failed to read HDB header from file: ");
00165 msg += m_fileName;
00166 OW_THROW(HDBException, msg.c_str());
00167 }
00168 f.close();
00169 if (::strncmp(m_hdrBlock.signature, OW_HDBSIGNATURE, HDBSIGLEN))
00170 {
00171 String msg("Invalid Format for HDB file: ");
00172 msg += m_fileName;
00173 OW_THROW(HDBException, msg.c_str());
00174 }
00175 if (m_hdrBlock.version < MinHDBVERSION || m_hdrBlock.version > HDBVERSION)
00176 {
00177 OW_THROW(HDBException, Format("Invalid version (%1) for file (%2). Expected (%3)", m_hdrBlock.version, m_fileName, HDBVERSION).c_str());
00178 }
00179 m_pindex = Index::createIndexObject();
00180 m_pindex->open(m_fileName.c_str());
00181 }
00183 Int32
00184 HDB::incVersion()
00185 {
00186 MutexLock l(m_guard);
00187 m_version++;
00188 return m_version;
00189 }
00191 HDBHandle
00192 HDB::getHandle()
00193 {
00194 MutexLock l(m_guard);
00195 if (!m_opened)
00196 {
00197 OW_THROW(HDBException, "Can't get handle from closed HDB");
00198 }
00199 const File& file = FileSystem::openFile(m_fileName);
00200 if (!file)
00201 {
00202 return HDBHandle();
00203 }
00204 m_hdlCount++;
00205 return HDBHandle(this, file);
00206 }
00208 void
00209 HDB::decHandleCount()
00210 {
00211 MutexLock l(m_guard);
00212 m_hdlCount--;
00213 }
00215 void
00216 HDB::setOffsets(File& file, Int32 firstRootOffset, Int32 lastRootOffset,
00217 Int32 firstFreeOffset)
00218 {
00219 MutexLock l(m_guard);
00220 m_hdrBlock.firstRoot = firstRootOffset;
00221 m_hdrBlock.lastRoot = lastRootOffset;
00222 m_hdrBlock.firstFree = firstFreeOffset;
00223 if (file.write(&m_hdrBlock, sizeof(m_hdrBlock), 0) != sizeof(m_hdrBlock))
00224 {
00225 OW_THROW(HDBException, "Failed to update offset on HDB");
00226 }
00227 }
00229 void
00230 HDB::setFirstRootOffSet(File& file, Int32 offset)
00231 {
00232 setOffsets(file, offset, m_hdrBlock.lastRoot, m_hdrBlock.firstFree);
00233 }
00235 void
00236 HDB::setLastRootOffset(File& file, Int32 offset)
00237 {
00238 setOffsets(file, m_hdrBlock.firstRoot, offset, m_hdrBlock.firstFree);
00239 }
00241 void
00242 HDB::setFirstFreeOffSet(File& file, Int32 offset)
00243 {
00244 setOffsets(file, m_hdrBlock.firstRoot, m_hdrBlock.lastRoot, offset);
00245 }
00247
00248
00249
00250 Int32
00251 HDB::findBlock(File& file, Int32 size)
00252 {
00253 MutexLock l(m_guard);
00254 Int32 offset = -1;
00255 HDBBlock fblk;
00256
00257
00258 if (m_hdrBlock.firstFree != -1)
00259 {
00260 Int32 coffset = m_hdrBlock.firstFree;
00261 while (true)
00262 {
00263 readBlock(fblk, file, coffset);
00264
00265
00266
00267 if (fblk.size >= static_cast<UInt32>(size))
00268 {
00269 offset = coffset;
00270 break;
00271 }
00272 if ((coffset = fblk.nextSib) == -1L)
00273 {
00274 break;
00275 }
00276 }
00277 }
00278
00279
00280 if (offset != -1)
00281 {
00282
00283 removeBlockFromFreeList(file, fblk);
00284 }
00285 else
00286 {
00287
00288
00289 if (file.seek(0L, SEEK_END) == -1L)
00290 {
00291 OW_THROW(HDBException, "Failed to seek to end of file");
00292 }
00293 if ((offset = file.tell()) == -1L)
00294 {
00295 OW_THROW(HDBException, "Failed to get offset in file");
00296 }
00297 }
00298 return offset;
00299 }
00301 void
00302 HDB::removeBlockFromFreeList(File& file, HDBBlock& fblk)
00303 {
00304 MutexLock l(m_guard);
00305 HDBBlock cblk;
00306
00307
00308 if (fblk.nextSib != -1)
00309 {
00310 readBlock(cblk, file, fblk.nextSib);
00311 cblk.prevSib = fblk.prevSib;
00312 writeBlock(cblk, file, fblk.nextSib);
00313 }
00314
00315
00316 if (fblk.prevSib != -1)
00317 {
00318 readBlock(cblk, file, fblk.prevSib);
00319 cblk.nextSib = fblk.nextSib;
00320 writeBlock(cblk, file, fblk.prevSib);
00321 }
00322 else
00323 {
00324
00325
00326 if (m_hdrBlock.firstFree != -1)
00327 {
00328 setFirstFreeOffSet(file, fblk.nextSib);
00329 }
00330 }
00331 }
00333
00334 void
00335 HDB::addBlockToFreeList(File& file, const HDBBlock& parmblk,
00336 Int32 offset)
00337 {
00338 MutexLock l(m_guard);
00339 HDBBlock fblk = parmblk;
00340 fblk.isFree = true;
00341
00342 if (m_hdrBlock.firstFree == -1)
00343 {
00344 fblk.nextSib = -1;
00345 fblk.prevSib = -1;
00346 writeBlock(fblk, file, offset);
00347 setFirstFreeOffSet(file, offset);
00348 return;
00349 }
00350 HDBBlock cblk;
00351 cblk.size = 0;
00352 Int32 coffset = m_hdrBlock.firstFree;
00353 Int32 loffset = 0;
00354
00355 while (coffset != -1)
00356 {
00357 loffset = coffset;
00358 readBlock(cblk, file, coffset);
00359 if (fblk.size <= cblk.size)
00360 {
00361 break;
00362 }
00363 coffset = cblk.nextSib;
00364 }
00365 if (coffset == -1)
00366 {
00367 cblk.nextSib = offset;
00368 writeBlock(cblk, file, loffset);
00369 fblk.prevSib = loffset;
00370 fblk.nextSib = -1;
00371 writeBlock(fblk, file, offset);
00372 }
00373 else
00374 {
00375 if (cblk.prevSib == -1)
00376 {
00377 setFirstFreeOffSet(file, offset);
00378 }
00379 else
00380 {
00381
00382
00383 HDBBlock tblk;
00384 readBlock(tblk, file, cblk.prevSib);
00385 tblk.nextSib = offset;
00386 writeBlock(tblk, file, cblk.prevSib);
00387 }
00388 fblk.nextSib = coffset;
00389 fblk.prevSib = cblk.prevSib;
00390 writeBlock(fblk, file, offset);
00391
00392 cblk.prevSib = offset;
00393 writeBlock(cblk, file, coffset);
00394 }
00395 }
00397
00398
00399
00400 void
00401 HDB::addRootNode(File& file, HDBBlock& fblk, Int32 offset)
00402 {
00403 MutexLock l(m_guard);
00404 fblk.parent = -1;
00405 fblk.nextSib = -1;
00406 if (m_hdrBlock.firstRoot == -1)
00407 {
00408 setOffsets(file, offset, offset, m_hdrBlock.firstFree);
00409 fblk.prevSib = -1;
00410 }
00411 else
00412 {
00413 fblk.prevSib = m_hdrBlock.lastRoot;
00414 HDBBlock cblk;
00415 readBlock(cblk, file, m_hdrBlock.lastRoot);
00416 cblk.nextSib = offset;
00417 writeBlock(cblk, file, m_hdrBlock.lastRoot);
00418 setLastRootOffset(file, offset);
00419 }
00420 writeBlock(fblk, file, offset);
00421 }
00423
00424 void
00425 HDB::writeBlock(HDBBlock& fblk, File& file, Int32 offset)
00426 {
00427 fblk.chkSum = 0;
00428 UInt32 chkSum = calcCheckSum(reinterpret_cast<unsigned char*>(&fblk), sizeof(fblk));
00429 fblk.chkSum = chkSum;
00430 int cc = file.write(&fblk, sizeof(fblk), offset);
00431 if (cc != sizeof(fblk))
00432 {
00433 OW_THROW(HDBException, "Failed to write block");
00434 }
00435 }
00437
00438 void
00439 HDB::readBlock(HDBBlock& fblk, const File& file, Int32 offset)
00440 {
00441 int cc = file.read(&fblk, sizeof(fblk), offset);
00442 if (cc != sizeof(fblk))
00443 {
00444 OW_THROW(HDBException, "Failed to read block");
00445 }
00446 UInt32 chkSum = fblk.chkSum;
00447 fblk.chkSum = 0;
00448 fblk.chkSum = calcCheckSum(reinterpret_cast<unsigned char*>(&fblk), sizeof(fblk));
00449 if (chkSum != fblk.chkSum)
00450 {
00451 OW_THROW(HDBException, "CORRUPT DATA? Invalid check sum in node");
00452 }
00453 }
00455 IndexEntry
00456 HDB::findFirstIndexEntry(const char* key)
00457 {
00458 if (!m_opened)
00459 {
00460 OW_THROW(HDBException, "HDB is not opened");
00461 }
00462 MutexLock il(m_indexGuard);
00463 return m_pindex->findFirst(key);
00464 }
00466 IndexEntry
00467 HDB::findNextIndexEntry()
00468 {
00469 if (!m_opened)
00470 {
00471 OW_THROW(HDBException, "HDB is not opened");
00472 }
00473 MutexLock il(m_indexGuard);
00474 return m_pindex->findNext();
00475 }
00477 IndexEntry
00478 HDB::findPrevIndexEntry()
00479 {
00480 if (!m_opened)
00481 {
00482 OW_THROW(HDBException, "HDB is not opened");
00483 }
00484 MutexLock il(m_indexGuard);
00485 return m_pindex->findPrev();
00486 }
00488 IndexEntry
00489 HDB::findIndexEntry(const char* key)
00490 {
00491 if (!m_opened)
00492 {
00493 OW_THROW(HDBException, "HDB is not opened");
00494 }
00495 MutexLock il(m_indexGuard);
00496 return m_pindex->find(key);
00497 }
00499 bool
00500 HDB::addIndexEntry(const char* key, Int32 offset)
00501 {
00502 if (!m_opened)
00503 {
00504 OW_THROW(HDBException, "HDB is not opened");
00505 }
00506 MutexLock il(m_indexGuard);
00507 return m_pindex->add(key, offset);
00508 }
00510 bool
00511 HDB::removeIndexEntry(const char* key)
00512 {
00513 if (!m_opened)
00514 {
00515 OW_THROW(HDBException, "HDB is not opened");
00516 }
00517 MutexLock il(m_indexGuard);
00518 return m_pindex->remove(key);
00519 }
00521 bool
00522 HDB::updateIndexEntry(const char* key, Int32 newOffset)
00523 {
00524 if (!m_opened)
00525 {
00526 OW_THROW(HDBException, "HDB is not opened");
00527 }
00528 MutexLock il(m_indexGuard);
00529 return m_pindex->update(key, newOffset);
00530 }
00532 void
00533 HDB::flushIndex()
00534 {
00535 if (m_opened)
00536 {
00537 MutexLock il(m_indexGuard);
00538 m_pindex->flush();
00539 }
00540 }
00542 static UInt32
00543 calcCheckSum(unsigned char* src, Int32 len)
00544 {
00545 UInt32 cksum = 0;
00546 Int32 i;
00547 for (i = 0; i < len; i++)
00548 {
00549 cksum += src[i];
00550 }
00551 return cksum;
00552 }
00554
00555 HDBHandle::HDBHandleData::~HDBHandleData()
00556 {
00557 try
00558 {
00559 m_file.close();
00560 m_pdb->decHandleCount();
00561 }
00562 catch (...)
00563 {
00564
00565 }
00566 }
00568 HDBHandle::HDBHandle() :
00569 m_pdata(NULL)
00570 {
00571 }
00573 HDBHandle::HDBHandle(HDB* pdb, const File& file) :
00574 m_pdata(new HDBHandleData(pdb, file))
00575 {
00576 }
00578 Int32
00579 HDBHandle::registerWrite()
00580 {
00581 m_pdata->m_writeDone = true;
00582 return m_pdata->m_pdb->incVersion();
00583 }
00585 void
00586 HDBHandle::flush()
00587 {
00588 if (m_pdata->m_writeDone)
00589 {
00590 m_pdata->m_pdb->flushIndex();
00591 m_pdata->m_file.flush();
00592 m_pdata->m_writeDone = false;
00593 }
00594 }
00596 HDBNode
00597 HDBHandle::getFirstRoot()
00598 {
00599 if (m_pdata->m_pdb->getFirstRootOffSet() > 0)
00600 {
00601 return HDBNode(m_pdata->m_pdb->getFirstRootOffSet(), *this);
00602 }
00603 return HDBNode();
00604 }
00606 HDBNode
00607 HDBHandle::getNode(const String& key)
00608 {
00609 if (!key.empty())
00610 {
00611 return HDBNode(key.c_str(), *this);
00612 }
00613 return HDBNode();
00614 }
00616 HDBNode
00617 HDBHandle::getParent(HDBNode& node)
00618 {
00619 if (node)
00620 {
00621 if (node.reload(*this))
00622 {
00623 if (node.getParentOffset() > 0)
00624 {
00625 return HDBNode(node.getParentOffset(), *this);
00626 }
00627 }
00628 }
00629 return HDBNode();
00630 }
00632 HDBNode
00633 HDBHandle::getFirstChild(HDBNode& node)
00634 {
00635 if (node)
00636 {
00637 if (node.reload(*this))
00638 {
00639 if (node.getFirstChildOffset() > 0)
00640 {
00641 return HDBNode(node.getFirstChildOffset(), *this);
00642 }
00643 }
00644 }
00645 return HDBNode();
00646 }
00648 HDBNode
00649 HDBHandle::getLastChild(HDBNode& node)
00650 {
00651 if (node)
00652 {
00653 if (node.reload(*this))
00654 {
00655 if (node.getLastChildOffset() > 0)
00656 {
00657 return HDBNode(node.getLastChildOffset(), *this);
00658 }
00659 }
00660 }
00661 return HDBNode();
00662 }
00664 HDBNode
00665 HDBHandle::getNextSibling(HDBNode& node)
00666 {
00667 if (node)
00668 {
00669 if (node.reload(*this))
00670 {
00671 if (node.getNextSiblingOffset() > 0)
00672 {
00673 return HDBNode(node.getNextSiblingOffset(), *this);
00674 }
00675 }
00676 }
00677 return HDBNode();
00678 }
00680 HDBNode
00681 HDBHandle::getPrevSibling(HDBNode& node)
00682 {
00683 if (node)
00684 {
00685 if (node.reload(*this))
00686 {
00687 if (node.getPrevSiblingOffset() > 0)
00688 {
00689 return HDBNode(node.getPrevSiblingOffset(), *this);
00690 }
00691 }
00692 }
00693 return HDBNode();
00694 }
00696 bool
00697 HDBHandle::addRootNode(HDBNode& node)
00698 {
00699 bool cc = false;
00700 if (node)
00701 {
00702 if (node.getOffset() > 0)
00703 {
00704 OW_THROW(HDBException, "node is already on file");
00705 }
00706 if (m_pdata->m_pdb->findIndexEntry(node.getKey().c_str()))
00707 {
00708 OW_THROW(HDBException, "key for node is already in index");
00709 }
00710 node.write(*this);
00711 cc = true;
00712 }
00713 return cc;
00714 }
00716 bool
00717 HDBHandle::addChild(HDBNode& parentNode, HDBNode& childNode)
00718 {
00719 bool cc = false;
00720 if (parentNode && childNode)
00721 {
00722 if (childNode.getOffset() > 0)
00723 {
00724 OW_THROW(HDBException, "child node already has a parent");
00725 }
00726 if (parentNode.getOffset() <= 0)
00727 {
00728 OW_THROW(HDBException, "parent node is not on file");
00729 }
00730 if (m_pdata->m_pdb->findIndexEntry(childNode.getKey().c_str()))
00731 {
00732 OW_THROW(HDBException, "key for node is already in index");
00733 }
00734 if (parentNode.reload(*this))
00735 {
00736 parentNode.addChild(*this, childNode);
00737 cc = true;
00738 }
00739 }
00740 return cc;
00741 }
00743 bool
00744 HDBHandle::addChild(const String& parentKey, HDBNode& childNode)
00745 {
00746 if (parentKey.empty())
00747 {
00748 return false;
00749 }
00750 HDBNode pnode = HDBNode(parentKey.c_str(), *this);
00751 if (pnode)
00752 {
00753 return addChild(pnode, childNode);
00754 }
00755 return false;
00756 }
00758 bool
00759 HDBHandle::removeNode(HDBNode& node)
00760 {
00761 bool cc = false;
00762 if (node && node.getOffset() > 0)
00763 {
00764 if (node.reload(*this))
00765 {
00766 node.remove(*this);
00767 cc = true;
00768 }
00769 }
00770 return cc;
00771 }
00773 bool
00774 HDBHandle::removeNode(const String& key)
00775 {
00776 bool cc = false;
00777 if (!key.empty())
00778 {
00779 HDBNode node(key.c_str(), *this);
00780 if (node)
00781 {
00782 node.remove(*this);
00783 }
00784 cc = true;
00785 }
00786 return cc;
00787 }
00789 bool
00790 HDBHandle::updateNode(HDBNode& node, Int32 dataLen, const unsigned char* data)
00791 {
00792 bool cc = false;
00793 if (node)
00794 {
00795
00796 if (node.getOffset() > 0)
00797 {
00798 if (node.reload(*this))
00799 {
00800 node.updateData(*this, dataLen, data);
00801 cc = true;
00802 }
00803 }
00804 else
00805 {
00806
00807 node.updateData(*this, dataLen, data);
00808 cc = true;
00809 }
00810 }
00811 return cc;
00812 }
00814 void
00815 HDBHandle::turnFlagsOn(HDBNode& node, UInt32 flags)
00816 {
00817 if (node)
00818 {
00819 if (node.getOffset() > 0)
00820 {
00821 if (node.reload(*this))
00822 {
00823 node.turnFlagsOn(*this, flags);
00824 }
00825 }
00826 else
00827 {
00828 node.turnFlagsOn(*this, flags);
00829 }
00830 }
00831 }
00833 void
00834 HDBHandle::turnFlagsOff(HDBNode& node, UInt32 flags)
00835 {
00836 if (node)
00837 {
00838 if (node.getOffset() > 0)
00839 {
00840 if (node.reload(*this))
00841 {
00842 node.turnFlagsOff(*this, flags);
00843 }
00844 }
00845 else
00846 {
00847 node.turnFlagsOff(*this, flags);
00848 }
00849 }
00850 }
00852 IndexEntry
00853 HDBHandle::findFirstIndexEntry(const char* key)
00854 {
00855 return m_pdata->m_pdb->findFirstIndexEntry(key);
00856 }
00858 IndexEntry
00859 HDBHandle::findNextIndexEntry()
00860 {
00861 return m_pdata->m_pdb->findNextIndexEntry();
00862 }
00864 IndexEntry
00865 HDBHandle::findPrevIndexEntry()
00866 {
00867 return m_pdata->m_pdb->findPrevIndexEntry();
00868 }
00870 IndexEntry
00871 HDBHandle::findIndexEntry(const char* key)
00872 {
00873 return m_pdata->m_pdb->findIndexEntry(key);
00874 }
00876 bool
00877 HDBHandle::addIndexEntry(const char* key, Int32 offset)
00878 {
00879 return m_pdata->m_pdb->addIndexEntry(key, offset);
00880 }
00882 bool
00883 HDBHandle::removeIndexEntry(const char* key)
00884 {
00885 return m_pdata->m_pdb->removeIndexEntry(key);
00886 }
00888 bool
00889 HDBHandle::updateIndexEntry(const char* key, Int32 newOffset)
00890 {
00891 return m_pdata->m_pdb->updateIndexEntry(key, newOffset);
00892 }
00893
00894 }
00895