Skip to content

Commit cc3346b

Browse files
authored
Merge pull request cmu-db#1401 from mbutrovich/friday_night
RWSet performance fixes, LockFreeArray performance fixes and tests
2 parents 25c6a79 + 69b4a33 commit cc3346b

File tree

6 files changed

+221
-135
lines changed

6 files changed

+221
-135
lines changed

src/common/container/lock_free_array.cpp

+16-27
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,10 @@
1010
//
1111
//===----------------------------------------------------------------------===//
1212

13-
#include <memory>
14-
1513
#include "common/container/lock_free_array.h"
14+
#include "common/internal_types.h"
1615
#include "common/logger.h"
1716
#include "common/macros.h"
18-
#include "common/internal_types.h"
1917

2018
namespace peloton {
2119

@@ -38,26 +36,24 @@ template <typename ValueType>
3836
LOCK_FREE_ARRAY_TYPE::~LockFreeArray() { lock_free_array.clear(); }
3937

4038
template <typename ValueType>
41-
bool LOCK_FREE_ARRAY_TYPE::Update(const std::size_t &offset, ValueType value) {
39+
void LOCK_FREE_ARRAY_TYPE::Update(const std::size_t &offset,
40+
const ValueType &value) {
4241
LOG_TRACE("Update at %lu", offset);
43-
PELOTON_ASSERT(lock_free_array.size() >= offset + 1);
42+
PELOTON_ASSERT(lock_free_array.size() > offset);
4443
lock_free_array.at(offset) = value;
45-
return true;
4644
}
4745

4846
template <typename ValueType>
49-
bool LOCK_FREE_ARRAY_TYPE::Append(ValueType value) {
47+
void LOCK_FREE_ARRAY_TYPE::Append(const ValueType &value) {
5048
LOG_TRACE("Appended value.");
5149
lock_free_array.push_back(value);
52-
return true;
5350
}
5451

5552
template <typename ValueType>
56-
bool LOCK_FREE_ARRAY_TYPE::Erase(const std::size_t &offset,
53+
void LOCK_FREE_ARRAY_TYPE::Erase(const std::size_t &offset,
5754
const ValueType &invalid_value) {
5855
LOG_TRACE("Erase at %lu", offset);
5956
lock_free_array.at(offset) = invalid_value;
60-
return true;
6157
}
6258

6359
template <typename ValueType>
@@ -73,23 +69,12 @@ ValueType LOCK_FREE_ARRAY_TYPE::FindValid(
7369
const std::size_t &offset, const ValueType &invalid_value) const {
7470
LOG_TRACE("Find Valid at %lu", offset);
7571

76-
std::size_t valid_array_itr = 0;
77-
std::size_t array_itr;
78-
auto lock_free_array_offset = lock_free_array.size();
79-
for (array_itr = 0; array_itr < lock_free_array_offset; array_itr++) {
80-
auto value = lock_free_array.at(array_itr);
81-
if (value != invalid_value) {
82-
// Check offset
83-
if (valid_array_itr == offset) {
84-
return value;
85-
}
86-
87-
// Update valid value count
88-
valid_array_itr++;
89-
}
72+
ValueType value = invalid_value;
73+
if ((lock_free_array.size() > offset)) {
74+
value = lock_free_array.at(offset);
9075
}
9176

92-
return invalid_value;
77+
return value;
9378
}
9479

9580
template <typename ValueType>
@@ -99,10 +84,14 @@ template <typename ValueType>
9984
bool LOCK_FREE_ARRAY_TYPE::IsEmpty() const { return lock_free_array.empty(); }
10085

10186
template <typename ValueType>
102-
void LOCK_FREE_ARRAY_TYPE::Clear() { lock_free_array.clear(); }
87+
void LOCK_FREE_ARRAY_TYPE::Clear() {
88+
// Intel docs: To free internal arrays, call shrink_to_fit() after clear().
89+
lock_free_array.clear();
90+
lock_free_array.shrink_to_fit();
91+
}
10392

10493
template <typename ValueType>
105-
bool LOCK_FREE_ARRAY_TYPE::Contains(const ValueType &value) {
94+
bool LOCK_FREE_ARRAY_TYPE::Contains(const ValueType &value) const {
10695
bool exists = false;
10796

10897
for (std::size_t array_itr = 0; array_itr < lock_free_array.size();

src/concurrency/timestamp_ordering_transaction_manager.cpp

+18-6
Original file line numberDiff line numberDiff line change
@@ -653,14 +653,19 @@ ResultType TimestampOrderingTransactionManager::CommitTransaction(
653653
// 3. install a new tuple for insert operations.
654654
// Iterate through each item pointer in the read write set
655655

656-
// TODO (Pooja): This might be inefficient since we will have to get the
657-
// tile_group_header for each entry. Check if this needs to be consolidated
656+
oid_t last_tile_group_id = INVALID_OID;
657+
storage::TileGroupHeader *tile_group_header = nullptr;
658+
658659
for (const auto &tuple_entry : rw_set) {
659660
ItemPointer item_ptr = tuple_entry.first;
660661
oid_t tile_group_id = item_ptr.block;
661662
oid_t tuple_slot = item_ptr.offset;
662663

663-
auto tile_group_header = storage_manager->GetTileGroup(tile_group_id)->GetHeader();
664+
if (tile_group_id != last_tile_group_id) {
665+
tile_group_header =
666+
storage_manager->GetTileGroup(tile_group_id)->GetHeader();
667+
last_tile_group_id = tile_group_id;
668+
}
664669

665670
if (tuple_entry.second == RWType::READ_OWN) {
666671
// A read operation has acquired ownership but hasn't done any further
@@ -805,13 +810,20 @@ ResultType TimestampOrderingTransactionManager::AbortTransaction(
805810
}
806811

807812
// Iterate through each item pointer in the read write set
808-
// TODO (Pooja): This might be inefficient since we will have to get the
809-
// tile_group_header for each entry. Check if this needs to be consolidated
813+
814+
oid_t last_tile_group_id = INVALID_OID;
815+
storage::TileGroupHeader *tile_group_header = nullptr;
816+
810817
for (const auto &tuple_entry : rw_set) {
811818
ItemPointer item_ptr = tuple_entry.first;
812819
oid_t tile_group_id = item_ptr.block;
813820
oid_t tuple_slot = item_ptr.offset;
814-
auto tile_group_header = storage_manager->GetTileGroup(tile_group_id)->GetHeader();
821+
822+
if (tile_group_id != last_tile_group_id) {
823+
tile_group_header =
824+
storage_manager->GetTileGroup(tile_group_id)->GetHeader();
825+
last_tile_group_id = tile_group_id;
826+
}
815827

816828
if (tuple_entry.second == RWType::READ_OWN) {
817829
// A read operation has acquired ownership but hasn't done any further

src/concurrency/transaction_context.cpp

+33-65
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,6 @@ TransactionContext::TransactionContext(const size_t thread_id,
6161
Init(thread_id, isolation, read_id, commit_id);
6262
}
6363

64-
TransactionContext::~TransactionContext() {}
65-
6664
void TransactionContext::Init(const size_t thread_id,
6765
const IsolationLevelType isolation,
6866
const cid_t &read_id, const cid_t &commit_id) {
@@ -78,103 +76,73 @@ void TransactionContext::Init(const size_t thread_id,
7876

7977
thread_id_ = thread_id;
8078

81-
isolation_level_ = isolation;
82-
8379
is_written_ = false;
8480

85-
insert_count_ = 0;
81+
isolation_level_ = isolation;
8682

87-
gc_set_.reset(new GCSet());
88-
gc_object_set_.reset(new GCObjectSet());
83+
gc_set_ = std::make_shared<GCSet>();
84+
gc_object_set_ = std::make_shared<GCObjectSet>();
8985

9086
on_commit_triggers_.reset();
9187
}
9288

9389
RWType TransactionContext::GetRWType(const ItemPointer &location) {
94-
RWType rw_type = RWType::INVALID;
95-
96-
auto rw_set_it = rw_set_.find(location);
90+
const auto rw_set_it = rw_set_.find(location);
9791
if (rw_set_it != rw_set_.end()) {
9892
return rw_set_it->second;
9993
}
100-
return rw_type;
94+
return RWType::INVALID;
10195
}
10296

10397
void TransactionContext::RecordRead(const ItemPointer &location) {
104-
98+
PELOTON_ASSERT(rw_set_.find(location) == rw_set_.end() ||
99+
(rw_set_[location] != RWType::DELETE &&
100+
rw_set_[location] != RWType::INS_DEL));
105101
auto rw_set_it = rw_set_.find(location);
106102
if (rw_set_it != rw_set_.end()) {
107-
UNUSED_ATTRIBUTE RWType rw_type = rw_set_it->second;
108-
PELOTON_ASSERT(rw_type != RWType::DELETE && rw_type != RWType::INS_DEL);
109103
return;
110104
}
111-
rw_set_.insert(rw_set_it, std::make_pair(location, RWType::READ));
105+
rw_set_[location] = RWType::READ;
112106
}
113107

114108
void TransactionContext::RecordReadOwn(const ItemPointer &location) {
115-
auto rw_set_it = rw_set_.find(location);
116-
if (rw_set_it != rw_set_.end()) {
117-
RWType rw_type = rw_set_it->second;
118-
PELOTON_ASSERT(rw_type != RWType::DELETE && rw_type != RWType::INS_DEL);
119-
if (rw_type == RWType::READ) {
120-
rw_set_it->second = RWType::READ_OWN;
121-
}
122-
} else {
123-
rw_set_.insert(rw_set_it, std::make_pair(location, RWType::READ_OWN));
124-
}
109+
PELOTON_ASSERT(rw_set_.find(location) == rw_set_.end() ||
110+
(rw_set_[location] != RWType::DELETE &&
111+
rw_set_[location] != RWType::INS_DEL));
112+
rw_set_[location] = RWType::READ_OWN;
125113
}
126114

127115
void TransactionContext::RecordUpdate(const ItemPointer &location) {
116+
PELOTON_ASSERT(rw_set_.find(location) == rw_set_.end() ||
117+
(rw_set_[location] != RWType::DELETE &&
118+
rw_set_[location] != RWType::INS_DEL));
128119
auto rw_set_it = rw_set_.find(location);
129-
if (rw_set_it != rw_set_.end()) {
130-
RWType rw_type = rw_set_it->second;
131-
if (rw_type == RWType::READ || rw_type == RWType::READ_OWN) {
132-
is_written_ = true;
133-
rw_set_it->second = RWType::UPDATE;
134-
} else if (rw_type == RWType::UPDATE || rw_type == RWType::INSERT) {
135-
return;
136-
} else {
137-
// DELETE or INS_DELETE
138-
PELOTON_ASSERT(false);
139-
}
140-
} else {
141-
rw_set_.insert(rw_set_it, std::make_pair(location, RWType::UPDATE));
120+
if (rw_set_it != rw_set_.end() && (rw_set_it->second == RWType::READ ||
121+
rw_set_it->second == RWType::READ_OWN)) {
122+
rw_set_it->second = RWType::UPDATE;
123+
is_written_ = true;
142124
}
125+
PELOTON_ASSERT(is_written_);
143126
}
144127

145128
void TransactionContext::RecordInsert(const ItemPointer &location) {
146-
auto rw_set_it = rw_set_.find(location);
147-
if (rw_set_it != rw_set_.end()) {
148-
PELOTON_ASSERT(false);
149-
return;
150-
}
151-
rw_set_.insert(rw_set_it, std::make_pair(location, RWType::INSERT));
152-
++insert_count_;
129+
PELOTON_ASSERT(rw_set_.find(location) == rw_set_.end());
130+
rw_set_[location] = RWType::INSERT;
131+
is_written_ = true;
153132
}
154133

155134
bool TransactionContext::RecordDelete(const ItemPointer &location) {
135+
PELOTON_ASSERT(rw_set_.find(location) == rw_set_.end() ||
136+
(rw_set_[location] != RWType::DELETE &&
137+
rw_set_[location] != RWType::INS_DEL));
156138
auto rw_set_it = rw_set_.find(location);
157-
if (rw_set_it != rw_set_.end()) {
158-
RWType rw_type = rw_set_it->second;
159-
160-
if (rw_type == RWType::READ || rw_type == RWType::READ_OWN) {
161-
rw_set_it->second = RWType::DELETE;
162-
is_written_ = true;
163-
return false;
164-
} else if (rw_type == RWType::UPDATE) {
165-
rw_set_it->second = RWType::DELETE;
166-
return false;
167-
} else if (rw_type == RWType::INSERT) {
168-
rw_set_it->second = RWType::INS_DEL;
169-
--insert_count_;
170-
return true;
171-
} else {
172-
// DELETE and INS_DEL
173-
PELOTON_ASSERT(false);
174-
return false;
175-
}
139+
if (rw_set_it != rw_set_.end() && rw_set_it->second == RWType::INSERT) {
140+
PELOTON_ASSERT(is_written_);
141+
rw_set_it->second = RWType::INS_DEL;
142+
return true;
176143
} else {
177-
rw_set_.insert(rw_set_it, std::make_pair(location, RWType::DELETE));
144+
rw_set_[location] = RWType::DELETE;
145+
is_written_ = true;
178146
return false;
179147
}
180148
}

src/include/common/container/lock_free_array.h

+57-23
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,6 @@
1212

1313
#pragma once
1414
#include "tbb/concurrent_vector.h"
15-
#include "tbb/tbb_allocator.h"
16-
#include <cstdlib>
17-
#include <cstring>
18-
#include <cstdio>
19-
#include <array>
20-
#include <atomic>
21-
#include <memory>
2215

2316
namespace peloton {
2417

@@ -35,33 +28,74 @@ class LockFreeArray {
3528
LockFreeArray();
3629
~LockFreeArray();
3730

38-
// Update a item
39-
bool Update(const std::size_t &offset, ValueType value);
40-
41-
// Append an item
42-
bool Append(ValueType value);
43-
44-
// Get a item
31+
/**
32+
* Assigns the provided value to the provided offset.
33+
*
34+
* @param offset Element offset to update
35+
* @param value Value to be assigned
36+
*/
37+
void Update(const std::size_t &offset, const ValueType &value);
38+
39+
/**
40+
* Appends an element to the end of the array
41+
*
42+
* @param value Value to be appended
43+
*/
44+
void Append(const ValueType &value);
45+
46+
/**
47+
* Returns the element at the offset
48+
*
49+
* @returns Element at offset
50+
*/
4551
ValueType Find(const std::size_t &offset) const;
4652

47-
// Get a valid item
53+
/**
54+
* Returns the element at the offset, or invalid_value if
55+
* the element does not exist.
56+
*
57+
* @param offset Element offset to access
58+
* @param invalid_value Sentinel value to return if element
59+
* does not exist or offset out of range
60+
* @returns Element at offset or invalid_value
61+
*/
4862
ValueType FindValid(const std::size_t &offset,
4963
const ValueType &invalid_value) const;
5064

51-
// Delete key from the lock_free_array
52-
bool Erase(const std::size_t &offset, const ValueType &invalid_value);
53-
54-
// Returns item count in the lock_free_array
65+
/**
66+
* Assigns the provided invalid_value to the provided offset.
67+
*
68+
* @param offset Element offset to update
69+
* @param invalid_value Invalid value to be assigned
70+
*/
71+
void Erase(const std::size_t &offset, const ValueType &invalid_value);
72+
73+
/**
74+
*
75+
* @return Number of elements in the underlying structure
76+
*/
5577
size_t GetSize() const;
5678

57-
// Checks if the lock_free_array is empty
79+
/**
80+
*
81+
* @return True if empty, false otherwise
82+
*/
5883
bool IsEmpty() const;
5984

60-
// Clear all elements and reset them to default value
85+
/**
86+
* Resets the underlying data structure to have 0 elements
87+
*/
6188
void Clear();
6289

63-
// Exists ?
64-
bool Contains(const ValueType &value);
90+
/**
91+
*
92+
* Check the lock-free array for the provided value.
93+
* O(n) time complexity.
94+
*
95+
* @param value value to search for
96+
* @return True if element present, false otherwise
97+
*/
98+
bool Contains(const ValueType &value) const;
6599

66100
private:
67101
// lock free array

0 commit comments

Comments
 (0)