From faca189b57d51ada0ec4b10b81ab0831a72aa0d1 Mon Sep 17 00:00:00 2001 From: Sekwon Date: Thu, 28 Feb 2019 16:46:55 -0600 Subject: [PATCH 1/4] [BUG FIX] The bug of FAIR algorithm is fixed. Current additional implementation for fixing FAIR bug is only reflected to insertion and search operations. Please change other code sections for other operations, such as remove and scan. --- concurrent/src/btree.h | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/concurrent/src/btree.h b/concurrent/src/btree.h index 5294e14..b089f70 100644 --- a/concurrent/src/btree.h +++ b/concurrent/src/btree.h @@ -113,7 +113,9 @@ class header{ uint8_t switch_counter; // 1 bytes uint8_t is_deleted; // 1 bytes int16_t last_index; // 2 bytes - std::mutex *mtx; // 8 bytes + std::mutex *mtx; // 8 bytes + entry_key_t highest; // 8 bytes + uint64_t dummy[3]; // 24 bytes friend class page; friend class btree; @@ -154,7 +156,7 @@ const int count_in_line = CACHE_LINE_SIZE / sizeof(entry); class page{ private: - header hdr; // header in persistent memory, 16 bytes + header hdr; // header in persistent memory, 64 bytes entry records[cardinality]; // slots in persistent memory, 16 bytes * n public: @@ -589,13 +591,23 @@ class page{ // If this node has a sibling node, if(hdr.sibling_ptr && (hdr.sibling_ptr != invalid_sibling)) { // Compare this key with the first key of the sibling - if(key > hdr.sibling_ptr->records[0].key) { - if(with_lock) { - hdr.mtx->unlock(); // Unlock the write lock + if (hdr.leftmost_ptr == NULL) { // leaf node + if(key > hdr.sibling_ptr->records[0].key) { + if(with_lock) { + hdr.mtx->unlock(); // Unlock the write lock + } + return hdr.sibling_ptr->store(bt, NULL, key, right, + true, with_lock, invalid_sibling); + } + } else { + if(key > hdr.sibling_ptr->hdr.highest) { // internal node + if(with_lock) { + hdr.mtx->unlock(); // Unlock the write lock + } + return hdr.sibling_ptr->store(bt, NULL, key, right, + true, with_lock, invalid_sibling); + } } - return hdr.sibling_ptr->store(bt, NULL, key, right, - true, with_lock, invalid_sibling); - } } register int num_entries = count(); @@ -629,6 +641,7 @@ class page{ sibling->insert_key(records[i].key, records[i].ptr, &sibling_cnt, false); } sibling->hdr.leftmost_ptr = (page*) records[m].ptr; + sibling->hdr.highest = records[m].key; } sibling->hdr.sibling_ptr = hdr.sibling_ptr; @@ -883,7 +896,7 @@ class page{ } while(hdr.switch_counter != previous_switch_counter); if((t = (char *)hdr.sibling_ptr) != NULL) { - if(key >= ((page *)t)->records[0].key) + if(key >= ((page *)t)->hdr.highest) return t; } From a5def6ca9885477ec977f4257943579248fb0ed3 Mon Sep 17 00:00:00 2001 From: Sekwon Lee Date: Thu, 14 Mar 2019 13:48:04 -0500 Subject: [PATCH 2/4] Fixing FAIR algorithm bug of leaf node split Solution: Adding middle key to new right sibling node --- concurrent/src/btree.h | 25 ++++++++----------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/concurrent/src/btree.h b/concurrent/src/btree.h index b089f70..5a48e25 100644 --- a/concurrent/src/btree.h +++ b/concurrent/src/btree.h @@ -115,7 +115,7 @@ class header{ int16_t last_index; // 2 bytes std::mutex *mtx; // 8 bytes entry_key_t highest; // 8 bytes - uint64_t dummy[3]; // 24 bytes + uint64_t dummy[1]; // 24 bytes friend class page; friend class btree; @@ -591,22 +591,12 @@ class page{ // If this node has a sibling node, if(hdr.sibling_ptr && (hdr.sibling_ptr != invalid_sibling)) { // Compare this key with the first key of the sibling - if (hdr.leftmost_ptr == NULL) { // leaf node - if(key > hdr.sibling_ptr->records[0].key) { - if(with_lock) { - hdr.mtx->unlock(); // Unlock the write lock - } - return hdr.sibling_ptr->store(bt, NULL, key, right, - true, with_lock, invalid_sibling); - } - } else { - if(key > hdr.sibling_ptr->hdr.highest) { // internal node - if(with_lock) { - hdr.mtx->unlock(); // Unlock the write lock - } - return hdr.sibling_ptr->store(bt, NULL, key, right, - true, with_lock, invalid_sibling); + if(key >= hdr.sibling_ptr->hdr.highest) { // internal node + if(with_lock) { + hdr.mtx->unlock(); // Unlock the write lock } + return hdr.sibling_ptr->store(bt, NULL, key, right, + true, with_lock, invalid_sibling); } } @@ -635,6 +625,7 @@ class page{ for(int i=m; iinsert_key(records[i].key, records[i].ptr, &sibling_cnt, false); } + sibling->hdr.highest = records[m].key; } else{ // internal node for(int i=m+1;i= ((page *)t)->records[0].key) + if((t = (char *)hdr.sibling_ptr) && key >= ((page *)t)->hdr.highest) return t; return NULL; From fe79323746124164e2536fbdee6acced0bdcb380 Mon Sep 17 00:00:00 2001 From: Sekwon Date: Thu, 14 Mar 2019 07:57:35 -0500 Subject: [PATCH 3/4] Adding new test code to run without input file --- concurrent/src/test2.cpp | 200 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 200 insertions(+) create mode 100644 concurrent/src/test2.cpp diff --git a/concurrent/src/test2.cpp b/concurrent/src/test2.cpp new file mode 100644 index 0000000..2e7a636 --- /dev/null +++ b/concurrent/src/test2.cpp @@ -0,0 +1,200 @@ +#include "btree.h" +#include +#include + +void clear_cache() { + // Remove cache + int size = 256*1024*1024; + char *garbage = new char[size]; + for(int i=0;i> keys[i]; + } + ifs.close(); + + // Initializing stats + clflush_cnt=0; + search_time_in_insert = 0; + clflush_time_in_insert = 0; + gettime_cnt = 0; + + std::default_random_engine generator; + std::uniform_int_distribution distribution (0, UINT64_MAX); + for (uint64_t i = 0; i < numData; i++) + keys[i] = distribution(generator); + + clock_gettime(CLOCK_MONOTONIC,&start); + + long half_num_data = numData / 2; + + // Warm-up! Insert half of input size + for(int i=0;ibtree_insert(keys[i], (char*) keys[i]); + } + cout << "Warm-up!" << endl; + + clock_gettime(CLOCK_MONOTONIC,&end); + long long elapsedTime = (end.tv_sec-start.tv_sec)*1000000000 + (end.tv_nsec-start.tv_nsec); + + clear_cache(); + + // Multithreading + vector> futures(n_threads); + + long data_per_thread = half_num_data / n_threads; + +#ifndef MIXED + // Insert + clock_gettime(CLOCK_MONOTONIC,&start); + + for(int tid = 0; tid < n_threads; tid++) { + int from = half_num_data + data_per_thread * tid; + int to = (tid == n_threads - 1) ? numData : from + data_per_thread; + + auto f = async(launch::async, [&bt, &keys](int from, int to){ + for(int i = from; i < to; ++i) + bt->btree_insert(keys[i], (char*) keys[i]); + }, from, to); + futures.push_back(move(f)); + } + for(auto &&f : futures) + if(f.valid()) + f.get(); + + clock_gettime(CLOCK_MONOTONIC,&end); + elapsedTime = (end.tv_sec-start.tv_sec)*1000000000 + (end.tv_nsec-start.tv_nsec); + cout<<"Concurrent inserting with " << n_threads << " threads (usec) : "<< elapsedTime / 1000 << endl; + + clear_cache(); + futures.clear(); + + // Search + clock_gettime(CLOCK_MONOTONIC,&start); + + for(int tid = 0; tid < n_threads; tid++) { + int from = data_per_thread * tid; + int to = (tid == n_threads - 1) ? half_num_data : from + data_per_thread; + + auto f = async(launch::async, [&bt, &keys](int from, int to){ + for(int i = from; i < to; ++i) + bt->btree_search(keys[i]); + }, from, to); + futures.push_back(move(f)); + } + for(auto &&f : futures) + if(f.valid()) + f.get(); + + clock_gettime(CLOCK_MONOTONIC,&end); + elapsedTime = (end.tv_sec-start.tv_sec)*1000000000 + (end.tv_nsec-start.tv_nsec); + cout<<"Concurrent searching with " << n_threads << " threads (usec) : "<< elapsedTime / 1000 << endl; +#else + clock_gettime(CLOCK_MONOTONIC,&start); + + for(int tid = 0; tid < n_threads; tid++) { + int from = half_num_data + data_per_thread * tid; + int to = (tid == n_threads - 1) ? numData : from + data_per_thread; + + auto f = async(launch::async, [&bt, &keys, &half_num_data](int from, int to){ + for(int i = from; i < to; ++i) { + int sidx = i - half_num_data; + + int jid = i % 4; + switch(jid) { + case 0: + bt->btree_insert(keys[i], (char*) keys[i]); + for(int j = 0; j < 4; j++) + bt->btree_search(keys[(sidx + j + jid * 8) % half_num_data]); + bt->btree_delete(keys[i]); + break; + case 1: + for(int j = 0; j < 3; j++) + bt->btree_search(keys[(sidx + j + jid * 8) % half_num_data]); + bt->btree_insert(keys[i], (char*) keys[i]); + bt->btree_search(keys[(sidx + 3 + jid * 8) % half_num_data]); + break; + case 2: + for(int j = 0; j < 2; j++) + bt->btree_search(keys[(sidx + j + jid * 8) % half_num_data]); + bt->btree_insert(keys[i], (char*) keys[i]); + for(int j = 2; j < 4; j++) + bt->btree_search(keys[(sidx + j + jid * 8) % half_num_data]); + break; + case 3: + for(int j = 0; j < 4; j++) + bt->btree_search(keys[(sidx + j + jid * 8) % half_num_data]); + bt->btree_insert(keys[i], (char*) keys[i]); + break; + default: + break; + } + } + }, from, to); + futures.push_back(move(f)); + + } + + for(auto &&f : futures) + if(f.valid()) + f.get(); + + clock_gettime(CLOCK_MONOTONIC,&end); + elapsedTime = (end.tv_sec-start.tv_sec)*1000000000 + (end.tv_nsec-start.tv_nsec); + cout<<"Concurrent inserting and searching with " << n_threads << " threads (usec) : "<< elapsedTime / 1000 << endl; +#endif + + delete bt; + delete[] keys; + + return 0; +} + + From db74fa8ad63c66026e0613309ce57f7d0c061f7a Mon Sep 17 00:00:00 2001 From: Sekwon Lee Date: Thu, 14 Mar 2019 17:40:30 -0500 Subject: [PATCH 4/4] [BUG FIX] FAIR algorithm of leafnode split Adding high key to every split leaf node --- concurrent/src/btree.h | 14 +-- concurrent/src/test2.cpp | 200 --------------------------------------- 2 files changed, 7 insertions(+), 207 deletions(-) delete mode 100644 concurrent/src/test2.cpp diff --git a/concurrent/src/btree.h b/concurrent/src/btree.h index 5a48e25..802708f 100644 --- a/concurrent/src/btree.h +++ b/concurrent/src/btree.h @@ -169,7 +169,7 @@ class page{ // this is called when tree grows page(page* left, entry_key_t key, page* right, uint32_t level = 0) { - hdr.leftmost_ptr = left; + hdr.leftmost_ptr = left; hdr.level = level; records[0].key = key; records[0].ptr = (char*) right; @@ -214,15 +214,15 @@ class page{ inline bool remove_key(entry_key_t key) { // Set the switch_counter - if(IS_FORWARD(hdr.switch_counter)) + if(IS_FORWARD(hdr.switch_counter)) ++hdr.switch_counter; bool shift = false; int i; for(i = 0; records[i].ptr != NULL; ++i) { if(!shift && records[i].key == key) { - records[i].ptr = (i == 0) ? - (char *)hdr.leftmost_ptr : records[i - 1].ptr; + records[i].ptr = (i == 0) ? + (char *)hdr.leftmost_ptr : records[i - 1].ptr; shift = true; } @@ -233,8 +233,8 @@ class page{ // flush uint64_t records_ptr = (uint64_t)(&records[i]); int remainder = records_ptr % CACHE_LINE_SIZE; - bool do_flush = (remainder == 0) || - ((((int)(remainder + sizeof(entry)) / CACHE_LINE_SIZE) == 1) && + bool do_flush = (remainder == 0) || + ((((int)(remainder + sizeof(entry)) / CACHE_LINE_SIZE) == 1) && ((remainder + sizeof(entry)) % CACHE_LINE_SIZE) != 0); if(do_flush) { clflush((char *)records_ptr, CACHE_LINE_SIZE); @@ -261,7 +261,7 @@ class page{ /* * Although we implemented the rebalancing of B+-Tree, it is currently blocked for the performance. * Please refer to the follow. - * Chi, P., Lee, W. C., & Xie, Y. (2014, August). + * Chi, P., Lee, W. C., & Xie, Y. (2014, August). * Making B+-tree efficient in PCM-based main memory. In Proceedings of the 2014 * international symposium on Low power electronics and design (pp. 69-74). ACM. */ diff --git a/concurrent/src/test2.cpp b/concurrent/src/test2.cpp deleted file mode 100644 index 2e7a636..0000000 --- a/concurrent/src/test2.cpp +++ /dev/null @@ -1,200 +0,0 @@ -#include "btree.h" -#include -#include - -void clear_cache() { - // Remove cache - int size = 256*1024*1024; - char *garbage = new char[size]; - for(int i=0;i> keys[i]; - } - ifs.close(); - - // Initializing stats - clflush_cnt=0; - search_time_in_insert = 0; - clflush_time_in_insert = 0; - gettime_cnt = 0; - - std::default_random_engine generator; - std::uniform_int_distribution distribution (0, UINT64_MAX); - for (uint64_t i = 0; i < numData; i++) - keys[i] = distribution(generator); - - clock_gettime(CLOCK_MONOTONIC,&start); - - long half_num_data = numData / 2; - - // Warm-up! Insert half of input size - for(int i=0;ibtree_insert(keys[i], (char*) keys[i]); - } - cout << "Warm-up!" << endl; - - clock_gettime(CLOCK_MONOTONIC,&end); - long long elapsedTime = (end.tv_sec-start.tv_sec)*1000000000 + (end.tv_nsec-start.tv_nsec); - - clear_cache(); - - // Multithreading - vector> futures(n_threads); - - long data_per_thread = half_num_data / n_threads; - -#ifndef MIXED - // Insert - clock_gettime(CLOCK_MONOTONIC,&start); - - for(int tid = 0; tid < n_threads; tid++) { - int from = half_num_data + data_per_thread * tid; - int to = (tid == n_threads - 1) ? numData : from + data_per_thread; - - auto f = async(launch::async, [&bt, &keys](int from, int to){ - for(int i = from; i < to; ++i) - bt->btree_insert(keys[i], (char*) keys[i]); - }, from, to); - futures.push_back(move(f)); - } - for(auto &&f : futures) - if(f.valid()) - f.get(); - - clock_gettime(CLOCK_MONOTONIC,&end); - elapsedTime = (end.tv_sec-start.tv_sec)*1000000000 + (end.tv_nsec-start.tv_nsec); - cout<<"Concurrent inserting with " << n_threads << " threads (usec) : "<< elapsedTime / 1000 << endl; - - clear_cache(); - futures.clear(); - - // Search - clock_gettime(CLOCK_MONOTONIC,&start); - - for(int tid = 0; tid < n_threads; tid++) { - int from = data_per_thread * tid; - int to = (tid == n_threads - 1) ? half_num_data : from + data_per_thread; - - auto f = async(launch::async, [&bt, &keys](int from, int to){ - for(int i = from; i < to; ++i) - bt->btree_search(keys[i]); - }, from, to); - futures.push_back(move(f)); - } - for(auto &&f : futures) - if(f.valid()) - f.get(); - - clock_gettime(CLOCK_MONOTONIC,&end); - elapsedTime = (end.tv_sec-start.tv_sec)*1000000000 + (end.tv_nsec-start.tv_nsec); - cout<<"Concurrent searching with " << n_threads << " threads (usec) : "<< elapsedTime / 1000 << endl; -#else - clock_gettime(CLOCK_MONOTONIC,&start); - - for(int tid = 0; tid < n_threads; tid++) { - int from = half_num_data + data_per_thread * tid; - int to = (tid == n_threads - 1) ? numData : from + data_per_thread; - - auto f = async(launch::async, [&bt, &keys, &half_num_data](int from, int to){ - for(int i = from; i < to; ++i) { - int sidx = i - half_num_data; - - int jid = i % 4; - switch(jid) { - case 0: - bt->btree_insert(keys[i], (char*) keys[i]); - for(int j = 0; j < 4; j++) - bt->btree_search(keys[(sidx + j + jid * 8) % half_num_data]); - bt->btree_delete(keys[i]); - break; - case 1: - for(int j = 0; j < 3; j++) - bt->btree_search(keys[(sidx + j + jid * 8) % half_num_data]); - bt->btree_insert(keys[i], (char*) keys[i]); - bt->btree_search(keys[(sidx + 3 + jid * 8) % half_num_data]); - break; - case 2: - for(int j = 0; j < 2; j++) - bt->btree_search(keys[(sidx + j + jid * 8) % half_num_data]); - bt->btree_insert(keys[i], (char*) keys[i]); - for(int j = 2; j < 4; j++) - bt->btree_search(keys[(sidx + j + jid * 8) % half_num_data]); - break; - case 3: - for(int j = 0; j < 4; j++) - bt->btree_search(keys[(sidx + j + jid * 8) % half_num_data]); - bt->btree_insert(keys[i], (char*) keys[i]); - break; - default: - break; - } - } - }, from, to); - futures.push_back(move(f)); - - } - - for(auto &&f : futures) - if(f.valid()) - f.get(); - - clock_gettime(CLOCK_MONOTONIC,&end); - elapsedTime = (end.tv_sec-start.tv_sec)*1000000000 + (end.tv_nsec-start.tv_nsec); - cout<<"Concurrent inserting and searching with " << n_threads << " threads (usec) : "<< elapsedTime / 1000 << endl; -#endif - - delete bt; - delete[] keys; - - return 0; -} - -