Skip to content
This repository was archived by the owner on Sep 27, 2019. It is now read-only.

Commit 58aa8c0

Browse files
committed
Lock_free_array refactor, documentation, and added more tests.
Refactor of RecordDelete to reduce lookups.
1 parent e8e5de7 commit 58aa8c0

File tree

4 files changed

+178
-46
lines changed

4 files changed

+178
-46
lines changed

src/common/container/lock_free_array.cpp

Lines changed: 11 additions & 12 deletions
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,23 @@ 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, const ValueType &value) {
4240
LOG_TRACE("Update at %lu", offset);
43-
PELOTON_ASSERT(lock_free_array.size() >= offset + 1);
41+
PELOTON_ASSERT(lock_free_array.size() > offset);
4442
lock_free_array.at(offset) = value;
45-
return true;
4643
}
4744

4845
template <typename ValueType>
49-
bool LOCK_FREE_ARRAY_TYPE::Append(ValueType value) {
46+
void LOCK_FREE_ARRAY_TYPE::Append(const ValueType &value) {
5047
LOG_TRACE("Appended value.");
5148
lock_free_array.push_back(value);
52-
return true;
5349
}
5450

5551
template <typename ValueType>
56-
bool LOCK_FREE_ARRAY_TYPE::Erase(const std::size_t &offset,
52+
void LOCK_FREE_ARRAY_TYPE::Erase(const std::size_t &offset,
5753
const ValueType &invalid_value) {
5854
LOG_TRACE("Erase at %lu", offset);
5955
lock_free_array.at(offset) = invalid_value;
60-
return true;
6156
}
6257

6358
template <typename ValueType>
@@ -88,10 +83,14 @@ template <typename ValueType>
8883
bool LOCK_FREE_ARRAY_TYPE::IsEmpty() const { return lock_free_array.empty(); }
8984

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

9392
template <typename ValueType>
94-
bool LOCK_FREE_ARRAY_TYPE::Contains(const ValueType &value) {
93+
bool LOCK_FREE_ARRAY_TYPE::Contains(const ValueType &value) const {
9594
bool exists = false;
9695

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

src/concurrency/transaction_context.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -122,11 +122,11 @@ void TransactionContext::RecordInsert(const ItemPointer &location) {
122122
void TransactionContext::RecordDelete(const ItemPointer &location) {
123123
PELOTON_ASSERT(rw_set_.count(location) == 0 ||
124124
(rw_set_[location] != RWType::DELETE && rw_set_[location] != RWType::INS_DEL));
125-
if (rw_set_[location] == RWType::INSERT) {
126-
rw_set_[location] = RWType::INS_DEL;
125+
auto rw_set_it = rw_set_.find(location);
126+
if (rw_set_it != rw_set_.end() && rw_set_it->second == RWType::INSERT) {
127+
rw_set_it->second = RWType::INS_DEL;
127128
}
128129
else {
129-
// READ, READ_OWN, UPDATE
130130
rw_set_[location] = RWType::DELETE;
131131
}
132132
}

src/include/common/container/lock_free_array.h

Lines changed: 57 additions & 23 deletions
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

test/common/lock_free_array_test.cpp

Lines changed: 107 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,7 @@ TEST_F(LockFreeArrayTests, BasicTest) {
3434

3535
size_t const element_count = 3;
3636
for (size_t element = 0; element < element_count; ++element ) {
37-
auto status = array.Append(element);
38-
EXPECT_TRUE(status);
37+
array.Append(element);
3938
}
4039

4140
auto array_size = array.GetSize();
@@ -55,8 +54,7 @@ TEST_F(LockFreeArrayTests, SharedPointerTest1) {
5554
size_t const element_count = 3;
5655
for (size_t element = 0; element < element_count; ++element ) {
5756
std::shared_ptr<oid_t> entry(new oid_t);
58-
auto status = array.Append(entry);
59-
EXPECT_TRUE(status);
57+
array.Append(entry);
6058
}
6159

6260
auto array_size = array.GetSize();
@@ -77,17 +75,15 @@ TEST_F(LockFreeArrayTests, SharedPointerTest2) {
7775
size_t const element_count = 10000;
7876
for (size_t element = 0; element < element_count; ++element ) {
7977
std::shared_ptr<oid_t> entry(new oid_t);
80-
auto status = array.Append(entry);
81-
EXPECT_TRUE(status);
78+
array.Append(entry);
8279
}
8380
});
8481

8582

8683
size_t const element_count = 10000;
8784
for (size_t element = 0; element < element_count; ++element ) {
8885
std::shared_ptr<oid_t> entry(new oid_t);
89-
auto status = array.Append(entry);
90-
EXPECT_TRUE(status);
86+
array.Append(entry);
9187
}
9288
t0.join();
9389

@@ -99,5 +95,108 @@ TEST_F(LockFreeArrayTests, SharedPointerTest2) {
9995
}
10096
}
10197

98+
TEST_F(LockFreeArrayTests, FindValidAndEraseTest) {
99+
100+
typedef uint32_t value_type;
101+
102+
{
103+
LockFreeArray<value_type> array;
104+
105+
value_type invalid_value = 6288;
106+
107+
size_t const element_count = 3;
108+
for (size_t element = 0; element < element_count; ++element ) {
109+
array.Append(element);
110+
}
111+
112+
// in range, valid
113+
EXPECT_EQ(2, array.FindValid(2, invalid_value));
114+
115+
// out of range
116+
EXPECT_EQ(invalid_value, array.FindValid(6, invalid_value));
117+
118+
array.Erase(2, invalid_value);
119+
120+
// in range, erased
121+
EXPECT_EQ(invalid_value, array.FindValid(2, invalid_value));
122+
}
123+
124+
}
125+
126+
TEST_F(LockFreeArrayTests, ClearAndIsEmptyTest) {
127+
128+
typedef uint32_t value_type;
129+
130+
{
131+
LockFreeArray<value_type> array;
132+
133+
EXPECT_TRUE(array.IsEmpty());
134+
135+
size_t const element_count = 3;
136+
for (size_t element = 0; element < element_count; ++element ) {
137+
array.Append(element);
138+
}
139+
140+
EXPECT_TRUE(array.Contains(2));
141+
142+
EXPECT_FALSE(array.IsEmpty());
143+
144+
array.Clear();
145+
146+
EXPECT_TRUE(array.IsEmpty());
147+
148+
149+
EXPECT_FALSE(array.Contains(2));
150+
151+
}
152+
153+
}
154+
155+
TEST_F(LockFreeArrayTests, ContainsTest) {
156+
157+
typedef uint32_t value_type;
158+
159+
{
160+
LockFreeArray<value_type> array;
161+
162+
EXPECT_FALSE(array.Contains(2));
163+
164+
size_t const element_count = 3;
165+
for (size_t element = 0; element < element_count; ++element ) {
166+
array.Append(element);
167+
}
168+
169+
EXPECT_TRUE(array.Contains(2));
170+
171+
array.Clear();
172+
173+
EXPECT_FALSE(array.Contains(2));
174+
175+
}
176+
177+
}
178+
179+
TEST_F(LockFreeArrayTests, UpdateTest) {
180+
181+
typedef uint32_t value_type;
182+
183+
{
184+
LockFreeArray<value_type> array;
185+
186+
size_t const element_count = 3;
187+
for (size_t element = 0; element < element_count; ++element ) {
188+
array.Append(element);
189+
}
190+
191+
EXPECT_EQ(2, array.Find(2));
192+
193+
array.Update(2, 6288);
194+
195+
EXPECT_EQ(6288, array.Find(2));
196+
197+
}
198+
199+
}
200+
102201
} // namespace test
103202
} // namespace peloton

0 commit comments

Comments
 (0)