diff --git a/run.cpp b/run.cpp index f7746a6..2f73b08 100644 --- a/run.cpp +++ b/run.cpp @@ -12,6 +12,7 @@ #include "trees/QuART_tail.h" #include "trees/QuART_stail.h" #include "trees/QuART_lil_can.h" +#include "trees/QuART_stail_reset.h" using namespace std; @@ -267,6 +268,48 @@ int main(int argc, char** argv) { cout << "Query time: " << query_time << " ns" << endl; } + // Output the times in csv format, including tree type + cout << insertion_time << "," << query_time << endl; + } else if (tree_type == "QuART_stail_reset") { + ART::QuART_stail_reset* tree = new ART::QuART_stail_reset(); + long long insertion_time = 0; + for (uint64_t i = 0; i < N; i++) { + uint8_t key[4]; + ART::loadKey(keys[i], key); + auto start = chrono::high_resolution_clock::now(); + tree->insert(key, keys[i]); + auto stop = chrono::high_resolution_clock::now(); + auto duration = + chrono::duration_cast(stop - start); + insertion_time += duration.count(); + } + + if (verbose) { + cout << "Tree type: " << tree_type << endl; + cout << "Insertion time: " << insertion_time << " ns" << endl; + } + + srand(time(0)); + + long long query_time = 0; + for (uint64_t i = 0; i < (N / 100); i++) { + int random = rand() % (maxval - minval + 1) + minval; + uint8_t key[4]; + ART::loadKey(keys[random], key); + auto start = chrono::high_resolution_clock::now(); + ART::ArtNode* leaf = tree->lookup(key); + auto stop = chrono::high_resolution_clock::now(); + auto duration = + chrono::duration_cast(stop - start); + query_time += duration.count(); + assert(ART::isLeaf(leaf) && + ART::getLeafValue(leaf) == keys[random]); + } + + if (verbose) { + cout << "Query time: " << query_time << " ns" << endl; + } + // Output the times in csv format, including tree type cout << insertion_time << "," << query_time << endl; } diff --git a/trees/QuART_stail.h b/trees/QuART_stail.h index 3047e99..b4de200 100644 --- a/trees/QuART_stail.h +++ b/trees/QuART_stail.h @@ -150,7 +150,7 @@ class QuART_stail : public ART { } } - private: + protected: /* Recursive insert function that does NOT change fp_leaf value */ void insert_recursive_preserve_fp(ArtNode* node, ArtNode** nodeRef, uint8_t key[], unsigned depth, diff --git a/trees/QuART_stail_reset.h b/trees/QuART_stail_reset.h new file mode 100644 index 0000000..27eb52f --- /dev/null +++ b/trees/QuART_stail_reset.h @@ -0,0 +1,185 @@ +#pragma once + +#include "../ART.h" +#include "../ArtNode.h" +#include "QuART_stail.h" + +namespace ART { + +class QuART_stail_reset : public QuART_stail { + private: + int reset_counter; + + public: + QuART_stail_reset() : QuART_stail(), reset_counter(300) {} + + void insert(uint8_t key[], uintptr_t value) { + /* Check if we can tail insert */ + + ArtNode* root = this->root; + + // If the root is null (i = 0), we will insert and change fp since + // keys[0] = 1 in all cases + if (root == nullptr) { + QuART_stail::insert_recursive_change_fp( + this->root, &this->root, key, 0, value, maxPrefixLength); + return; + } + + // Store leafValue, it will be used a lot + int leafValue = getLeafValue(this->fp_leaf); + + // For each byte in the key excluding the last byte, + // check if it matches the corresponding byte in the leaf value + for (size_t i = 0; i < maxPrefixLength - 1; i++) { + // Find the byte of leaf in the i'th position (i = [0, 1, 2]) + uint8_t leafByte = + (leafValue >> (8 * (maxPrefixLength - 1 - i))) & 0xFF; + + // If the bytes match, continue to next byte + if (key[i] == leafByte) { + continue; + } + // If the key byte is less than the leaf value, we do insert without + // tracking the path, as this will never be the new fp path. We + // only update the current fp information if it changes. + else if (key[i] < leafByte) { + QuART_stail::insert_recursive_preserve_fp( + this->root, &this->root, key, 0, value, maxPrefixLength); + return; + } + // Key byte is greater than leaf byte + else { + // If we are at the first byte + if (i == 0) { + // If the key is a bridge value, change fp + if ((key[0] == leafByte + 1) && (key[1] == 0) && + (key[2] == 0) && ((leafValue >> 8 * 2) & 0xFF) == 255 && + ((leafValue >> 8) & 0xFF) == 255) { + this->fp_path = {this->root}; + this->fp_path_length = 1; + QuART_stail::insert_recursive_change_fp( + this->root, &this->root, key, 0, value, + maxPrefixLength); + return; + } + // If it is not a bridge value and counter ended, force fp change + else if (this->reset_counter == 0) { + this->reset_counter = 300; // reset counter + this->insert_recursive_change_fp( + this->root, &this->root, key, 0, value, + maxPrefixLength); + return; + } + // If it is not a bridge value, insert without changing + else { + this->reset_counter--; // decrement counter + QuART_stail::insert_recursive_preserve_fp( + this->root, &this->root, key, 0, value, + maxPrefixLength); + return; + } + } + // If we are at the second byte + else if (i == 1) { + // If the key is a bridge value, change fp + if ((key[1] == leafByte + 1) && (key[2] == 0) && + (key[0] == ((leafValue >> 8 * 3) & 0xFF)) && + ((leafValue >> 8) & 0xFF) == 255) { + this->fp_path = {this->root}; + this->fp_path_length = 1; + QuART_stail::insert_recursive_change_fp( + this->root, &this->root, key, 0, value, + maxPrefixLength); + return; + } + // If it is not a bridge value and counter ended, force fp change + else if (this->reset_counter == 0) { + this->reset_counter = 300; // reset counter + this->insert_recursive_change_fp( + this->root, &this->root, key, 0, value, + maxPrefixLength); + return; + } + // If it is not a bridge value, insert without changing + else { + this->reset_counter--; // decrement counter + QuART_stail::insert_recursive_preserve_fp( + this->root, &this->root, key, 0, value, + maxPrefixLength); + return; + } + } + // If we are at the third byte + else { + // If the key is a bridge value, change fp + if ((key[2] == leafByte + 1) && + (key[0] == ((leafValue >> 8 * 3) & 0xFF)) && + (key[1] == ((leafValue >> 8 * 2) & 0xFF))) { + this->fp_path = {this->root}; + this->fp_path_length = 1; + QuART_stail::insert_recursive_change_fp( + this->root, &this->root, key, 0, value, + maxPrefixLength); + return; + } + // If it is not a bridge value and counter ended, force fp change + else if (this->reset_counter == 0) { + this->reset_counter = 300; // reset counter + this->insert_recursive_change_fp( + this->root, &this->root, key, 0, value, + maxPrefixLength); + return; + } + // If it is not a bridge value, insert without changing + else { + this->reset_counter--; // decrement counter + QuART_stail::insert_recursive_preserve_fp( + this->root, &this->root, key, 0, value, + maxPrefixLength); + return; + } + } + } + } + + /* If the algorithm reaches here, it means that fp insert will happen */ + + // If depth is at maxPrefixLength - 1, we do not need to worry about + // leaf expansion of prefix mismatch, we can directly insert the new + // leaf into fp node + if (this->fp_depth == maxPrefixLength - 1) { + // Insert leaf into fp + ArtNode* newNode = makeLeaf(value); + switch (this->fp->type) { + case NodeType4: + static_cast(this->fp)->stailInsertNode4PreserveFp( + this, this->fp_ref, key[fp_depth], newNode); + break; + case NodeType16: + static_cast(this->fp)->stailInsertNode16PreserveFp( + this, this->fp_ref, key[fp_depth], newNode); + break; + case NodeType48: + static_cast(this->fp)->stailInsertNode48PreserveFp( + this, this->fp_ref, key[fp_depth], newNode); + break; + case NodeType256: + static_cast(this->fp)->insertNode256( + this, this->fp_ref, key[fp_depth], newNode); + break; + } + return; + } + // Else, we call the recursive function and let it handle leaf expansion + // or prefix mismatch if there is one. If not, it will directly insert + // into the fp + else { + QuART_stail::insert_recursive_preserve_fp( + this->fp, this->fp_ref, key, fp_depth, value, maxPrefixLength); + return; + } + } +}; + +} // namespace ART \ No newline at end of file