/*============================================================================= # Filename: VNode.cpp # Author: Bookug Lobert # Mail: zengli-bookug@pku.edu.cn # Last Modified: 2016-04-11 14:08 # Description: by liyouhuan and hanshuo =============================================================================*/ #include "VNode.h" using namespace std; VNode::VNode() { //this->is_leaf = false; //this->is_root = false; //this->child_num = 0; this->flag = 0; this->self_file_line = -1; this->father_file_line = -1; this->child_file_lines = new int[VNode::MAX_CHILD_NUM]; for(int i = 0; i < VNode::MAX_CHILD_NUM; i ++) { this->child_file_lines[i] = -1; } InitLock(); } VNode::VNode(bool _is_leaf) { //this->is_leaf = false; //this->is_root = false; //this->child_num = 0; this->flag = 0; this->self_file_line = -1; this->father_file_line = -1; if(_is_leaf) { this->child_file_lines = NULL; //return; } else { this->AllocChilds(); } InitLock(); } VNode::~VNode() { delete[] this->child_file_lines; this->child_file_lines = NULL; #ifdef THREAD_VSTREE_ON pthread_mutex_destroy(&(this->node_lock)); #endif } void VNode::AllocChilds() { this->child_file_lines = new int[VNode::MAX_CHILD_NUM]; for(int i = 0; i < VNode::MAX_CHILD_NUM; i ++) { this->child_file_lines[i] = -1; } } void VNode::InitLock() { #ifdef THREAD_VSTREE_ON pthread_mutexattr_t attr; pthread_mutexattr_init(&attr); pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); pthread_mutex_init(&(this->node_lock), &attr); #endif } void VNode::setFlag(unsigned _flag) { this->flag = _flag; } bool VNode::isDirty() const { return this->flag & VNode::DIRTY_PART; } void VNode::setDirty(bool _flag) { if(_flag) { this->flag |= VNode::DIRTY_PART; } else { this->flag &= VNode::DEL_DIRTY_PART; } } bool VNode::isLeaf() const { return this->flag & VNode::LEAF_PART; } bool VNode::isRoot() const { return this->flag & VNode::ROOT_PART; } bool VNode::isFull() const { return (this->getChildNum() == VNode::MAX_CHILD_NUM - 1); // need one slot for splitting node. } void VNode::setAsLeaf(bool _isLeaf) { if(_isLeaf) { this->flag |= VNode::LEAF_PART; } else { this->flag &= VNode::DEL_LEAF_PART; } } void VNode::setAsRoot(bool _isRoot) { if(_isRoot) { this->flag |= VNode::ROOT_PART; } else { this->flag &= VNode::DEL_ROOT_PART; } //this->setDirty(); } int VNode::getChildNum() const { //return this->child_num; return this->flag & VNode::NUM_PART; } int VNode::getFileLine() const { return this->self_file_line; } int VNode::getFatherFileLine() const { return this->father_file_line; } int VNode::getChildFileLine(int _i) const { return this->child_file_lines[_i]; } void VNode::setChildNum(int _num) { //this->child_num = _num; this->flag &= VNode::DEL_NUM_PART; this->flag |= _num; //this->setDirty(); } void VNode::setFileLine(int _line) { this->self_file_line = _line; //this->setDirty(); } void VNode::setFatherFileLine(int _line) { this->father_file_line = _line; } void VNode::setChildFileLine(int _i, int _line) { this->child_file_lines[_i] = _line; } const SigEntry& VNode::getEntry()const { return this->entry; } const SigEntry& VNode::getChildEntry(int _i)const { return this->child_entries[_i]; } void VNode::setEntry(const SigEntry _entry) { this->entry = _entry; } void VNode::setChildEntry(int _i, const SigEntry _entry) { /* _entry should not be an ref, because if _entry is an ref, * it's possible that _entry is exactly an ref of this->child_entries[i] * !!!!!!!!!!!!!!!!!!!! */ SigEntry _sig(_entry); this->child_entries[_i] = _sig; //debug // { // if (this->getFileLine() == 0 && this->getChildFileLine(_i) == 153) // { // Util::logging("set node 0's child node 153's entry:"); // Util::logging(Signature::BitSet2str(this->child_entries[_i].getEntitySig().entityBitSet)); // } // } } VNode* VNode::getFather(LRUCache& _nodeBuffer)const { if (this->isRoot()) { return NULL; } return _nodeBuffer.get(this->getFatherFileLine()); } VNode* VNode::getChild(int _i, LRUCache& _nodeBuffer)const { if (this->isLeaf()) { return NULL; } return _nodeBuffer.get(this->getChildFileLine(_i)); } /* add one child entry to this node. when splitting this node, can add a new entry to it. */ bool VNode::addChildEntry(const SigEntry _entry, bool _is_splitting) { //if (this->isFull() && !_is_splitting) //{ //cerr<< "error, can not add child entry when the node is full, in VNode::addChildEntry." << endl; //return false; //} int child_num = this->getChildNum(); this->setChildEntry(child_num, _entry); //this->child_num ++; this->setChildNum(child_num+1); return true; } /* add one child node to this node. when splitting this node, can add a new child to it. */ bool VNode::addChildNode(VNode* _p_child_node, bool _is_splitting) { //if (this->isFull() && !_is_splitting) //{ //cerr<< "error, can not add child when the node is full. @VNode::addChildNode" << endl; //return false; //} //if (_p_child_node == NULL) //{ //cerr<< "error, can not add child when the child node pointer is NULL. @VNode::addChildNode" << endl; //return false; //} int child_num = this->getChildNum(); _p_child_node->setFatherFileLine(this->self_file_line); _p_child_node->setDirty(); this->setChildFileLine(child_num, _p_child_node->getFileLine()); this->addChildEntry( _p_child_node->getEntry(), _is_splitting); //NOTICE:this function calls addChildEntry(), which already add the child_num //this->child_num ++; return true; } bool VNode::removeChild(int _i) { int child_num = this->getChildNum(); if (_i < 0 || _i >= child_num) { cerr<< "error, illegal child index. @VNode::removeChild" << endl; return false; } if(this->isLeaf()) { for (int j = _i + 1; j < child_num; ++j) { child_entries[j-1] = child_entries[j]; //child_file_lines[j-1] = child_file_lines[j]; } } else { for (int j = _i + 1; j < child_num; ++j) { child_entries[j-1] = child_entries[j]; child_file_lines[j-1] = child_file_lines[j]; } } //this->child_num --; this->setChildNum(child_num-1); return true; } int VNode::getIndexInFatherNode(LRUCache& _nodeBuffer) { VNode * fatherNodePtr = this->getFather(_nodeBuffer); if (fatherNodePtr == NULL) { return 0; } int n = fatherNodePtr->getChildNum(); for (int i = 0; i < n; i++) { if (fatherNodePtr->getChildFileLine(i) == this->self_file_line) { #ifdef THREAD_VSTREE_ON pthread_mutex_unlock(&(fatherNodePtr->node_lock)); #endif return i; } } #ifdef THREAD_VSTREE_ON pthread_mutex_unlock(&(fatherNodePtr->node_lock)); #endif cerr << "error, can not find rank in father node. @VNode::getIndexInFatherNode" << endl; return 0; } void VNode::refreshSignature() { EntitySig sig; int child_num = this->getChildNum(); for (int i = 0; i < child_num; i++) { sig |= this->child_entries[i].getEntitySig(); } // refresh self node's signature. if (sig != this->entry.getEntitySig()) { SigEntry newEntry(sig, this->entry.getEntityId()); this->setEntry(newEntry); } } void VNode::refreshAncestorSignature(LRUCache& _nodeBuffer) { // refresh self node's signature. this->refreshSignature(); // refresh father node's signature. #ifdef DEBUG_VSTREE //cout<<"VNode::refreshAncestorSignature() - to get father"<getFather(_nodeBuffer); if (fatherNodePtr == NULL) { if (!this->isRoot()) cerr << "error, can not find father node. @VNode::refreshSignature" << endl; return; } int rank = this->getIndexInFatherNode(_nodeBuffer); if (fatherNodePtr->getChildEntry(rank).getEntitySig() != this->entry.getEntitySig()) { fatherNodePtr->setDirty(); fatherNodePtr->setChildEntry(rank, this->entry); fatherNodePtr->refreshAncestorSignature(_nodeBuffer); } #ifdef THREAD_VSTREE_ON pthread_mutex_unlock(&(fatherNodePtr->node_lock)); #endif } bool VNode::retrieveChild(vector& _child_vec, const EntitySig _filter_sig, LRUCache& _nodeBuffer) { if (this->isLeaf()) { cerr << "error, can not retrieve children from a leaf node.@VNode::retrieveChild" << endl; return false; } int child_num = this->getChildNum(); for (int i = 0; i < child_num; i++) { if (this->child_entries[i].cover(_filter_sig)) { _child_vec.push_back(this->getChild(i, _nodeBuffer)); } } return true; } bool VNode::retrieveEntry(vector& _entry_vec, const EntitySig _filter_sig, LRUCache& _nodeBuffer) { if (!this->isLeaf()) { cerr << "error, can not retrieve entries from a non-leaf node. @VNode::retrieveEntry" << endl; return false; } int child_num = this->getChildNum(); for (int i = 0 ; i < child_num; i++) { if (this->child_entries[i].cover(_filter_sig)) { _entry_vec.push_back(this->child_entries[i]); } } return false; } bool VNode::checkState() { if (this->getFileLine() < 0) return false; int child_num = this->getChildNum(); for (int i = 0; i < child_num; i++) if (!this->isLeaf() && this->getChildFileLine(i) < 0) { return false; } return true; } std::string VNode::to_str() { std::stringstream _ss; _ss << "VNode:" << endl; _ss << "\tEntityID:" << entry.getEntityId() << endl; _ss << "\tisLeaf:" << this->isLeaf() << endl; _ss << "\tisRoot:" << this->isRoot() << endl; _ss << "\tfileline:" << this->self_file_line << endl; _ss << "\tsignature:" << Signature::BitSet2str(this->entry.getEntitySig().entityBitSet ) << endl; int child_num = this->getChildNum(); _ss << "\tchildNum:" << child_num << endl << "\t"; for(int i = 0; i < child_num; i ++) { if(! this->isLeaf()){ _ss << "[" << this->getChildFileLine(i) << "]\t"; } else { _ss << i << "[*" << this->getChildEntry(i).getEntityId() << "]\t"; _ss << (this->getChildEntry(i).to_str()) << endl; } _ss << "\t" << this->child_entries[i].to_str() << endl; } _ss << endl << endl; return _ss.str(); } //TODO: keep a lock for each node, but not write to disk bool VNode::readNode(FILE* _fp) { int ret = fread(&(this->flag), sizeof(unsigned), 1, _fp); if(ret == 0) //the edn of file { return false; } fread(&(this->self_file_line), sizeof(int), 1, _fp); //cout<<"to read node: "<self_file_line<father_file_line), sizeof(int), 1, _fp); fread(&(this->entry), sizeof(SigEntry), 1, _fp); //for(int i = 0; i < VNode::MAX_CHILD_NUM; ++i) //{ //fread(&(this->child_entries[i]), sizeof(SigEntry), 1, _fp); //} fread(this->child_entries, sizeof(SigEntry), VNode::MAX_CHILD_NUM, _fp); if(!this->isLeaf()) //internal node { this->child_file_lines = new int[VNode::MAX_CHILD_NUM]; //for(int i = 0; i < VNode::MAX_CHILD_NUM; ++i) //{ //fread(&(this->child_file_lines[i]), sizeof(int), 1, _fp); //} fread(this->child_file_lines, sizeof(int), VNode::MAX_CHILD_NUM, _fp); } else //move to the end of the node block { fseek(_fp, sizeof(int) * VNode::MAX_CHILD_NUM, SEEK_CUR); } //this->setDirty(false); return true; } bool VNode::writeNode(FILE* _fp) { //clean, then no need to write //if(!this->isDirty()) //{ //return true; //} //NOTICE:already dealed in LRUCache //this->setDirty(false); //cout<<"to write node: "<self_file_line<flag), sizeof(unsigned), 1, _fp); fwrite(&(this->self_file_line), sizeof(int), 1, _fp); //NOTICE: this must be a old node(not new inserted node), so no need to write more if(this->self_file_line < 0) { return true; } fwrite(&(this->father_file_line), sizeof(int), 1, _fp); fwrite(&(this->entry), sizeof(SigEntry), 1, _fp); //for(int i = 0; i < VNode::MAX_CHILD_NUM; ++i) //{ //fwrite(&(this->child_entries[i]), sizeof(SigEntry), 1, _fp); //} fwrite(this->child_entries, sizeof(SigEntry), VNode::MAX_CHILD_NUM, _fp); if(!this->isLeaf()) //internal node { //for(int i = 0; i < VNode::MAX_CHILD_NUM; ++i) //{ //fwrite(&(this->child_file_lines[i]), sizeof(int), 1, _fp); //} fwrite(this->child_file_lines, sizeof(int), VNode::MAX_CHILD_NUM, _fp); } else //move to the end of the node block { //fseek(_fp, sizeof(int) * VNode::MAX_CHILD_NUM, SEEK_CUR); int t = 0; for(int i = 0; i < VNode::MAX_CHILD_NUM; ++i) { fwrite(&t, sizeof(int), 1, _fp); } } return true; }