/*
* Update() - Update a key-value pair
* This function returns false if
* 1. Traverse is aborted
* 2. oldValue does not exist
* 3. newValue already exist
*/boolUpdate(constKeyType&key,constValueType&oldValue,constValueType&newValue){bwt_printf("Update called\n");#ifdef BWTREE_DEBUG
update_op_count.fetch_add(1);#endif
EpochNode*epoch_node_p=epoch_manager.JoinEpoch();/* update will be performed iff old value is exist and new value is not.
* YOU MUST use previous one to be precise, but in order to make test case easier
* we DO NOT check for the newValue's existence
*/while(1){Contextcontext{key};std::pair<int,bool>index_pair;// Navigate leaf nodes to check whether the key-oldValue & key-newValue// pair existsconststd::pair<constKeyValuePair*,constKeyValuePair*>item_p= \
Traverse(&context,&oldValue,&newValue,&index_pair);/* There is 3 reason for update() to fail
* 1. Traverse() aborted, returning <nullptr, nullptr>
* 2. <key,oldValue> does not exist
* 3. <key,newValue> already exist
*/// if(item_p.first == nullptr || item_p.second != nullptr) {if(item_p.first==nullptr){#ifdef BWTREE_DEBUG
update_abort_count.fetch_add(1);#endif
epoch_manager.LeaveEpoch(epoch_node_p);returnfalse;}NodeSnapshot*snapshot_p=GetLatestNodeSnapshot(&context);// We will CAS on top of thisconstBaseNode*node_p=snapshot_p->node_p;NodeIDnode_id=snapshot_p->node_id;constLeafDeleteNode*delete_node_p= \
LeafInlineAllocateOfType(LeafDeleteNode,node_p,key,oldValue,node_p,index_pair);constLeafInsertNode*insert_node_p= \
LeafInlineAllocateOfType(LeafInsertNode,node_p,key,newValue,delete_node_p,index_pair);// delete_node_p on 5th argv.boolret=InstallNodeToReplace(node_id,insert_node_p,node_p);// install insert_node_pif(ret==true){break;}else{delete_node_p->~LeafDeleteNode();insert_node_p->~LeafInsertNode();}}// delete & insert key-oldValue pair doneepoch_manager.LeaveEpoch(epoch_node_p);returntrue;}
Traverse()
conststd::pair<constKeyValuePair*,constKeyValuePair*>Traverse(Context*context_p,constValueType*value_p1,constValueType*value_p2,std::pair<int,bool>*index_pair_p){// For value collection it always returns nullptrconstKeyValuePair*found_pair_p1=nullptr;constKeyValuePair*found_pair_p2=nullptr;retry_traverse:assert(context_p->abort_flag==false);#ifdef BWTREE_DEBUG
assert(context_p->current_level==-1);#endif
// This is the serialization point for reading/writing root nodeNodeIDstart_node_id=root_id.load();// This is used to identify root nodes// NOTE: We set current snapshot since in LoadNodeID() or read opt.// version the parent node snapshot will be overwritten with this child// node snapshot//// NOTE 2: We could not use GetLatestNodeSnapshot() here since it checks// current_level, which is -1 at this pointcontext_p->current_snapshot.node_id=INVALID_NODE_ID;// We need to call this even for root node since there could// be split delta posted on to root nodeLoadNodeID(start_node_id,context_p);// There could be an abort here, and we could not directly jump// to Init state since we would like to do some clean up or// statistics after abortingif(context_p->abort_flag==true){gotoabort_traverse;}bwt_printf("Successfully loading root node ID\n");while(1){NodeIDchild_node_id=NavigateInnerNode(context_p);// Navigate could abort since it might go to another NodeID// if there is a split delta and the key is >= split keyif(context_p->abort_flag==true){bwt_printf("Navigate Inner Node abort. ABORT\n");// If NavigateInnerNode() aborts then it returns INVALID_NODE_ID// as a double check// This is the only situation that this function returns// INVALID_NODE_IDassert(child_node_id==INVALID_NODE_ID);gotoabort_traverse;}// This might load a leaf child// Also LoadNodeID() does not guarantee the node bound matches// search key. Since we could readjust using the split side link// during Navigate...Node()LoadNodeID(child_node_id,context_p);if(context_p->abort_flag==true){bwt_printf("LoadNodeID aborted. ABORT\n");gotoabort_traverse;}// This is the node we have just loadedNodeSnapshot*snapshot_p=GetLatestNodeSnapshot(context_p);if(snapshot_p->IsLeaf()==true){bwt_printf("The next node is a leaf\n");break;}}//while(1)if(value_p1==nullptr&&value_p2==nullptr){// We are using an iterator just to get a leaf pageassert(index_pair_p==nullptr);// If both are nullptr then we just navigate the sibling chain// to find the correct node with the correct range// And then the iterator will consolidate the node without actually// going down with a specific keyNavigateSiblingChain(context_p);}else{// If a value is given then use this value to Traverse down leaf// page to find whether the value exists or notif(value_p1!=nullptr)found_pair_p1=NavigateLeafNode(context_p,*value_p1,index_pair_p);if(value_p2!=nullptr)found_pair_p2=NavigateLeafNode(context_p,*value_p2,index_pair_p);}if(context_p->abort_flag==true){bwt_printf("NavigateLeafNode() or NavigateSiblingChain()"" aborts. ABORT\n");gotoabort_traverse;}#ifdef BWTREE_DEBUG
bwt_printf("Found leaf node. Abort count = %d, level = %d\n",context_p->abort_counter,context_p->current_level);#endif
// If there is no abort then we could safely returnreturnstd::make_pair(found_pair_p1,found_pair_p2);abort_traverse:#ifdef BWTREE_DEBUG
assert(context_p->current_level>=0);context_p->current_level=-1;context_p->abort_counter++;#endif
// This is used to identify root nodecontext_p->current_snapshot.node_id=INVALID_NODE_ID;context_p->abort_flag=false;gotoretry_traverse;assert(false);returnstd::make_pair(nullptr,nullptr);}