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