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_HDBNode.hpp"
00038 #include "OW_HDB.hpp"
00039 #include "OW_AutoPtr.hpp"
00040 #include <cstring>
00041 #include <cerrno>
00042
00043 namespace OW_NAMESPACE
00044 {
00045
00047 HDBNode::HDBNodeData::HDBNodeData() :
00048 m_blk(), m_key(), m_bfrLen(0), m_bfr(NULL), m_offset(-1L), m_version(0)
00049 {
00050 ::memset(&m_blk, 0, sizeof(m_blk));
00051 }
00053 HDBNode::HDBNodeData::HDBNodeData(const HDBNodeData& x) :
00054 IntrusiveCountableBase(x), m_blk(x.m_blk), m_key(x.m_key), m_bfrLen(x.m_bfrLen), m_bfr(NULL),
00055 m_offset(x.m_offset), m_version(0)
00056 {
00057 if (m_bfrLen > 0)
00058 {
00059 m_bfr = new unsigned char[m_bfrLen];
00060 ::memcpy(m_bfr, x.m_bfr, m_bfrLen);
00061 }
00062 }
00064 HDBNode::HDBNodeData::~HDBNodeData()
00065 {
00066 delete [] m_bfr;
00067 }
00069 HDBNode::HDBNodeData&
00070 HDBNode::HDBNodeData::operator= (const HDBNode::HDBNodeData& x)
00071 {
00072 m_blk = x.m_blk;
00073 m_key = x.m_key;
00074 m_version = x.m_version;
00075 delete [] m_bfr;
00076 m_bfr = NULL;
00077 m_bfrLen = x.m_bfrLen;
00078 if (m_bfrLen > 0)
00079 {
00080 m_bfr = new unsigned char[m_bfrLen];
00081 ::memcpy(m_bfr, x.m_bfr, m_bfrLen);
00082 }
00083 m_offset = x.m_offset;
00084 return *this;
00085 }
00087 HDBNode::HDBNode(const char* key, HDBHandle& hdl) :
00088 m_pdata(NULL)
00089 {
00090 if (!key || !hdl)
00091 {
00092 return;
00093 }
00094 IndexEntry ientry = hdl.findIndexEntry(key);
00095 if (!ientry)
00096 {
00097 return;
00098 }
00099 read(ientry.offset, hdl);
00100 }
00102 HDBNode::HDBNode(Int32 offset, HDBHandle& hdl) :
00103 m_pdata(NULL)
00104 {
00105 if (!hdl || offset <= 0)
00106 {
00107 return;
00108 }
00109 read(offset, hdl);
00110 }
00112 HDBNode::HDBNode(const String& key, int dataLen,
00113 const unsigned char* data) :
00114 m_pdata(NULL)
00115 {
00116 if (key.empty())
00117 {
00118 return;
00119 }
00120 m_pdata = new HDBNodeData;
00121 m_pdata->m_offset = -1;
00122 m_pdata->m_version = 0;
00123 m_pdata->m_key = key;
00124 if (dataLen && data != NULL)
00125 {
00126 m_pdata->m_bfr = new unsigned char[dataLen];
00127 ::memcpy(m_pdata->m_bfr, data, dataLen);
00128 }
00129 else
00130 {
00131 dataLen = 0;
00132 }
00133 m_pdata->m_bfrLen = dataLen;
00134 m_pdata->m_blk.isFree = false;
00135 m_pdata->m_blk.keyLength = m_pdata->m_key.length()+1;
00136 m_pdata->m_blk.size = 0;
00137 m_pdata->m_blk.nextSib = -1;
00138 m_pdata->m_blk.prevSib = -1;
00139 m_pdata->m_blk.parent = -1;
00140 m_pdata->m_blk.firstChild = -1;
00141 m_pdata->m_blk.lastChild = -1;
00142 m_pdata->m_blk.dataLength = m_pdata->m_key.length() + 1 + dataLen;
00143 }
00145 void
00146 HDBNode::read(Int32 offset, HDBHandle& hdl)
00147 {
00148 if (offset <= 0 || !hdl)
00149 {
00150 OW_THROW(HDBException, "Invalid offset to read node from, db is most likely corrupt.");
00151 }
00152 File file = hdl.getFile();
00153 HDBBlock fblk;
00154
00155 setNull();
00156
00157 HDB::readBlock(fblk, file, offset);
00158
00159 if (fblk.isFree)
00160 {
00161 return;
00162 }
00163 char* kbfr = new char[fblk.keyLength];
00164 if (file.read(kbfr, fblk.keyLength) != size_t(fblk.keyLength))
00165 {
00166 delete [] kbfr;
00167 OW_THROW_ERRNO_MSG(HDBException, "Failed to read key for node");
00168 }
00169
00170
00171 String key(String::E_TAKE_OWNERSHIP, kbfr, fblk.keyLength - 1);
00172 unsigned char* bfr = NULL;
00173 int dataLen = fblk.dataLength - fblk.keyLength;
00174 if (dataLen > 0)
00175 {
00176 bfr = new unsigned char[dataLen];
00177 if (file.read(bfr, dataLen) != size_t(dataLen))
00178 {
00179 delete [] bfr;
00180 OW_THROW_ERRNO_MSG(HDBException, "Failed to data for node");
00181 }
00182 }
00183 m_pdata = new HDBNodeData;
00184 m_pdata->m_offset = offset;
00185 m_pdata->m_bfr = bfr;
00186 m_pdata->m_bfrLen = dataLen;
00187 m_pdata->m_blk = fblk;
00188 m_pdata->m_key = key;
00189 m_pdata->m_version = hdl.getHDB()->getVersion();
00190 }
00192 bool
00193 HDBNode::reload(HDBHandle& hdl)
00194 {
00195
00196 if (!m_pdata)
00197 {
00198 return false;
00199 }
00200
00201 if (m_pdata->m_offset <= 0)
00202 {
00203 return true;
00204 }
00205
00206
00207 if (hdl.getHDB()->getVersion() == m_pdata->m_version)
00208 {
00209 return true;
00210 }
00211 File file = hdl.getFile();
00212 HDBBlock fblk;
00213 Int32 offset = m_pdata->m_offset;
00214 try
00215 {
00216 HDB::readBlock(fblk, file, offset);
00217 }
00218 catch (const HDBException&)
00219 {
00220 setNull();
00221 return false;
00222 }
00223
00224 if (fblk.isFree)
00225 {
00226 setNull();
00227 return false;
00228 }
00229 AutoPtrVec<char> kbfr(new char[fblk.keyLength]);
00230 if (file.read(kbfr.get(), fblk.keyLength) != size_t(fblk.keyLength))
00231 {
00232 return false;
00233 }
00234 if (!m_pdata->m_key.equals(kbfr.get()))
00235 {
00236
00237
00238 setNull();
00239 return false;
00240 }
00241 int dataLen = fblk.dataLength - fblk.keyLength;
00242 if (fblk.dataLength != m_pdata->m_blk.dataLength)
00243 {
00244
00245
00246 delete [] m_pdata->m_bfr;
00247 m_pdata->m_bfr = NULL;
00248 }
00249
00250
00251
00252 if (dataLen > 0)
00253 {
00254 if (m_pdata->m_bfr == NULL)
00255 {
00256 m_pdata->m_bfr = new unsigned char[dataLen];
00257 }
00258 if (file.read(m_pdata->m_bfr, dataLen) != size_t(dataLen))
00259 {
00260 setNull();
00261 return false;
00262 }
00263 }
00264 m_pdata->m_bfrLen = dataLen;
00265 m_pdata->m_blk = fblk;
00266 m_pdata->m_version = hdl.getHDB()->getVersion();
00267 return true;
00268 }
00270 bool
00271 HDBNode::turnFlagsOn(HDBHandle& hdl, UInt32 flags)
00272 {
00273 if (!m_pdata)
00274 {
00275 return false;
00276 }
00277 bool cc = false;
00278 flags |= m_pdata->m_blk.flags;
00279 if (flags != m_pdata->m_blk.flags)
00280 {
00281 m_pdata->m_blk.flags = flags;
00282 if (m_pdata->m_offset > 0)
00283 {
00284 write(hdl);
00285 }
00286 cc = true;
00287 }
00288 return cc;
00289 }
00291 bool
00292 HDBNode::turnFlagsOff(HDBHandle& hdl, UInt32 flags)
00293 {
00294 if (!m_pdata)
00295 {
00296 return false;
00297 }
00298 bool cc = false;
00299 flags = m_pdata->m_blk.flags & (~flags);
00300 if (flags != m_pdata->m_blk.flags)
00301 {
00302 m_pdata->m_blk.flags = flags;
00303 if (m_pdata->m_offset > 0)
00304 {
00305 write(hdl);
00306 }
00307 cc = true;
00308 }
00309 return cc;
00310 }
00312 bool
00313 HDBNode::updateData(HDBHandle& hdl, int dataLen, const unsigned char* data)
00314 {
00315 bool cc = false;
00316 if (m_pdata)
00317 {
00318
00319
00320 if (m_pdata->m_offset > 0)
00321 {
00322 if (!reload(hdl))
00323 {
00324
00325 return false;
00326 }
00327 }
00328 cc = true;
00329
00330 if (dataLen != m_pdata->m_bfrLen)
00331 {
00332 delete [] m_pdata->m_bfr;
00333 m_pdata->m_bfr = NULL;
00334 m_pdata->m_bfrLen = 0;
00335 }
00336 if (dataLen > 0 && data != NULL)
00337 {
00338 if (m_pdata->m_bfr == NULL)
00339 {
00340 m_pdata->m_bfr = new unsigned char[dataLen];
00341 }
00342 m_pdata->m_bfrLen = dataLen;
00343 ::memcpy(m_pdata->m_bfr, data, dataLen);
00344 }
00345
00346 if (m_pdata->m_offset > 0)
00347 {
00348 write(hdl);
00349 }
00350 }
00351 return cc;
00352 }
00354 Int32
00355 HDBNode::write(HDBHandle& hdl, EWriteHeaderFlag onlyHeader)
00356 {
00357 if (!m_pdata)
00358 {
00359 OW_THROW(HDBException, "Internal error: Cannot write null node");
00360 }
00361 bool newRecord = false;
00362 m_pdata->m_blk.keyLength = m_pdata->m_key.length() + 1;
00363 m_pdata->m_blk.dataLength = m_pdata->m_bfrLen + m_pdata->m_key.length() + 1;
00364 File file = hdl.getFile();
00365 HDB* phdb = hdl.getHDB();
00366 int totalSize = m_pdata->m_blk.dataLength + sizeof(m_pdata->m_blk);
00367 m_pdata->m_blk.isFree = false;
00368 if (m_pdata->m_offset <= 0)
00369 {
00370 newRecord = true;
00371 m_pdata->m_blk.size = totalSize;
00372 m_pdata->m_offset = phdb->findBlock(file, totalSize);
00373 if (m_pdata->m_blk.parent <= 0)
00374 {
00375 phdb->addRootNode(file, m_pdata->m_blk, m_pdata->m_offset);
00376 }
00377 else
00378 {
00379 HDB::writeBlock(m_pdata->m_blk, file, m_pdata->m_offset);
00380 }
00381
00382 if (!hdl.addIndexEntry(m_pdata->m_key.c_str(), m_pdata->m_offset))
00383 {
00384 OW_THROW(HDBException, "Failed to write index entry");
00385 }
00386 }
00387 else
00388 {
00389
00390
00391 if (totalSize > int(m_pdata->m_blk.size))
00392 {
00393 HDBBlock node = m_pdata->m_blk;
00394 phdb->addBlockToFreeList(file, node, m_pdata->m_offset);
00395 m_pdata->m_blk.size = totalSize;
00396 updateOffsets(hdl, phdb->findBlock(file, totalSize));
00397 }
00398 HDB::writeBlock(m_pdata->m_blk, file, m_pdata->m_offset);
00399 }
00400 if (onlyHeader == false || newRecord == true)
00401 {
00402
00403 if (file.write(m_pdata->m_key.c_str(), m_pdata->m_key.length()+1)
00404 != m_pdata->m_key.length()+1)
00405 {
00406 OW_THROW_ERRNO_MSG(HDBException, "Failed to write node key");
00407 }
00408 if (file.write(m_pdata->m_bfr, m_pdata->m_bfrLen)
00409 != size_t(m_pdata->m_bfrLen))
00410 {
00411 OW_THROW_ERRNO_MSG(HDBException, "Failed to write node data");
00412 }
00413 }
00414 m_pdata->m_version = hdl.registerWrite();
00415 return m_pdata->m_offset;
00416 }
00418 void
00419 HDBNode::updateOffsets(HDBHandle& hdl, Int32 offset)
00420 {
00421 if (offset <= 0L || !m_pdata || !hdl)
00422 {
00423 return;
00424 }
00425 HDB* pdb = hdl.getHDB();
00426 File file = hdl.getFile();
00427 HDBBlock fblk;
00428 if (m_pdata->m_blk.prevSib > 0)
00429 {
00430 HDB::readBlock(fblk, file, m_pdata->m_blk.prevSib);
00431 fblk.nextSib = offset;
00432 HDB::writeBlock(fblk, file, m_pdata->m_blk.prevSib);
00433 }
00434 if (m_pdata->m_blk.nextSib > 0)
00435 {
00436 HDB::readBlock(fblk, file, m_pdata->m_blk.nextSib);
00437 fblk.prevSib = offset;
00438 HDB::writeBlock(fblk, file, m_pdata->m_blk.nextSib);
00439 }
00440 if (m_pdata->m_blk.parent > 0)
00441 {
00442 HDB::readBlock(fblk, file, m_pdata->m_blk.parent);
00443 bool doUpdate = false;
00444 if (fblk.firstChild == m_pdata->m_offset)
00445 {
00446 fblk.firstChild = offset;
00447 doUpdate = true;
00448 }
00449 if (fblk.lastChild == m_pdata->m_offset)
00450 {
00451 fblk.lastChild = offset;
00452 doUpdate = true;
00453 }
00454 if (doUpdate)
00455 {
00456 HDB::writeBlock(fblk, file, m_pdata->m_blk.parent);
00457 }
00458 }
00459 else
00460 {
00461 if (pdb->getFirstRootOffSet() == m_pdata->m_offset)
00462 {
00463 pdb->setFirstRootOffSet(file, offset);
00464 }
00465 if (pdb->getLastRootOffset() == m_pdata->m_offset)
00466 {
00467 pdb->setLastRootOffset(file, offset);
00468 }
00469 }
00470
00471 Int32 coffset = m_pdata->m_blk.firstChild;
00472 while (coffset > 0)
00473 {
00474 HDB::readBlock(fblk, file, coffset);
00475 fblk.parent = offset;
00476 HDB::writeBlock(fblk, file, coffset);
00477 coffset = fblk.nextSib;
00478 }
00479
00480 hdl.updateIndexEntry(m_pdata->m_key.c_str(), offset);
00481 m_pdata->m_offset = offset;
00482 }
00484 void
00485 HDBNode::addChild(HDBHandle& hdl, HDBNode& arg)
00486 {
00487 if (!arg)
00488 {
00489 return;
00490 }
00491
00492
00493
00494 if (m_pdata->m_offset <= 0)
00495 {
00496 write(hdl);
00497 }
00498
00499
00500
00501
00502 if (arg.m_pdata->m_offset > 0)
00503 {
00504
00505
00506 if (arg.m_pdata->m_blk.parent == m_pdata->m_offset)
00507 {
00508 arg.write(hdl);
00509 return;
00510 }
00511 OW_THROW(HDBException, "Child node already has a parent. db may be corrupt");
00512 }
00513 arg.m_pdata->m_blk.prevSib = m_pdata->m_blk.lastChild;
00514 arg.m_pdata->m_blk.nextSib = -1;
00515 arg.m_pdata->m_blk.parent = m_pdata->m_offset;
00516 Int32 newNodeOffset = arg.write(hdl);
00517 File file = hdl.getFile();
00518
00519
00520 if (m_pdata->m_blk.lastChild > 0)
00521 {
00522 HDBBlock node;
00523 HDB::readBlock(node, file, m_pdata->m_blk.lastChild);
00524
00525 node.nextSib = newNodeOffset;
00526
00527 HDB::writeBlock(node, file, m_pdata->m_blk.lastChild);
00528 }
00529 m_pdata->m_blk.lastChild = arg.m_pdata->m_offset;
00530 if (m_pdata->m_blk.firstChild <= 0)
00531 {
00532 m_pdata->m_blk.firstChild = m_pdata->m_blk.lastChild;
00533 }
00534 write(hdl);
00535 }
00537 bool
00538 HDBNode::remove(HDBHandle& hdl)
00539 {
00540
00541 if (m_pdata->m_offset <= 0)
00542 {
00543 return false;
00544 }
00545 File file = hdl.getFile();
00546 HDB* pdb = hdl.getHDB();
00547 HDBBlock fblk;
00548
00549 Int32 coffset = m_pdata->m_blk.lastChild;
00550 Int32 toffset;
00551 while (coffset > 0)
00552 {
00553 HDB::readBlock(fblk, file, coffset);
00554 toffset = coffset;
00555 coffset = fblk.prevSib;
00556
00557 removeBlock(hdl, fblk, toffset);
00558 }
00559
00560 if (m_pdata->m_blk.nextSib > 0)
00561 {
00562 HDB::readBlock(fblk, file, m_pdata->m_blk.nextSib);
00563 fblk.prevSib = m_pdata->m_blk.prevSib;
00564 HDB::writeBlock(fblk, file, m_pdata->m_blk.nextSib);
00565 }
00566
00567 if (m_pdata->m_blk.prevSib > 0)
00568 {
00569 HDB::readBlock(fblk, file, m_pdata->m_blk.prevSib);
00570 fblk.nextSib = m_pdata->m_blk.nextSib;
00571 HDB::writeBlock(fblk, file, m_pdata->m_blk.prevSib);
00572 }
00573
00574 if (m_pdata->m_blk.parent > 0)
00575 {
00576
00577 HDB::readBlock(fblk, file, m_pdata->m_blk.parent);
00578 bool changed = false;
00579
00580
00581 if (fblk.firstChild == m_pdata->m_offset)
00582 {
00583 changed = true;
00584 fblk.firstChild = m_pdata->m_blk.nextSib;
00585 }
00586
00587
00588 if (fblk.lastChild == m_pdata->m_offset)
00589 {
00590 changed = true;
00591 fblk.lastChild = m_pdata->m_blk.prevSib;
00592 }
00593
00594 if (changed)
00595 {
00596 HDB::writeBlock(fblk, file, m_pdata->m_blk.parent);
00597 }
00598 }
00599 else
00600 {
00601
00602 if (pdb->getFirstRootOffSet() == m_pdata->m_offset)
00603 {
00604 pdb->setFirstRootOffSet(file, m_pdata->m_blk.nextSib);
00605 }
00606 if (pdb->getLastRootOffset() == m_pdata->m_offset)
00607 {
00608 pdb->setLastRootOffset(file, m_pdata->m_blk.prevSib);
00609 }
00610 }
00611
00612 pdb->addBlockToFreeList(file, m_pdata->m_blk, m_pdata->m_offset);
00613
00614 hdl.removeIndexEntry(m_pdata->m_key.c_str());
00615 m_pdata->m_offset = -1;
00616 m_pdata->m_blk.isFree = true;
00617 m_pdata->m_blk.parent = -1;
00618 m_pdata->m_blk.firstChild = -1;
00619 m_pdata->m_blk.lastChild = -1;
00620 m_pdata->m_blk.prevSib = -1;
00621 m_pdata->m_blk.nextSib = -1;
00622 m_pdata->m_blk.size = 0;
00623 hdl.registerWrite();
00624 return true;
00625 }
00627
00628
00629
00630
00631
00632 #define LMAX(a, b) ((int(a) > int(b)) ? (a) : (b))
00633 void
00634 HDBNode::removeBlock(HDBHandle& hdl, HDBBlock& fblk, Int32 offset)
00635 {
00636 AutoPtrVec<unsigned char>
00637 pbfr(new unsigned char[LMAX(sizeof(fblk), fblk.keyLength)]);
00638 File file = hdl.getFile();
00639 Int32 coffset = fblk.lastChild;
00640 if (coffset > 0)
00641 {
00642 while (coffset > 0)
00643 {
00644 HDB::readBlock(*(reinterpret_cast<HDBBlock*>(pbfr.get())), file, coffset);
00645
00646 Int32 toffset = coffset;
00647
00648 coffset = (reinterpret_cast<HDBBlock*>(pbfr.get()))->prevSib;
00649
00650 removeBlock(hdl, *(reinterpret_cast<HDBBlock*>(pbfr.get())), toffset);
00651 }
00652 }
00653
00654 if (file.read(pbfr.get(), fblk.keyLength, offset + sizeof(fblk))
00655 != size_t(fblk.keyLength))
00656 {
00657 OW_THROW_ERRNO_MSG(HDBException, "Failed to read node's key for removal");
00658 }
00659
00660 hdl.removeIndexEntry(reinterpret_cast<const char*>(pbfr.get()));
00661
00662 hdl.getHDB()->addBlockToFreeList(file, fblk, offset);
00663 }
00664
00665 }
00666