-
Notifications
You must be signed in to change notification settings - Fork 618
RWSet performance fixes, LockFreeArray performance fixes and tests #1401
Changes from 14 commits
a9847aa
96431ee
a8b1b0c
76e0998
e8e5de7
58aa8c0
344c914
8afd1b7
6779ba7
07d75b3
c37e6ef
2aed22b
ac0a760
ad0381d
2db074c
d5583f0
30fddc2
21253c4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -61,8 +61,6 @@ TransactionContext::TransactionContext(const size_t thread_id, | |
Init(thread_id, isolation, read_id, commit_id); | ||
} | ||
|
||
TransactionContext::~TransactionContext() {} | ||
|
||
void TransactionContext::Init(const size_t thread_id, | ||
const IsolationLevelType isolation, | ||
const cid_t &read_id, const cid_t &commit_id) { | ||
|
@@ -80,101 +78,67 @@ void TransactionContext::Init(const size_t thread_id, | |
|
||
isolation_level_ = isolation; | ||
|
||
is_written_ = false; | ||
|
||
insert_count_ = 0; | ||
|
||
gc_set_.reset(new GCSet()); | ||
gc_object_set_.reset(new GCObjectSet()); | ||
gc_set_ = std::make_shared<GCSet>(); | ||
gc_object_set_ = std::make_shared<GCObjectSet>(); | ||
|
||
on_commit_triggers_.reset(); | ||
} | ||
|
||
RWType TransactionContext::GetRWType(const ItemPointer &location) { | ||
RWType rw_type = RWType::INVALID; | ||
|
||
auto rw_set_it = rw_set_.find(location); | ||
const auto rw_set_it = rw_set_.find(location); | ||
if (rw_set_it != rw_set_.end()) { | ||
return rw_set_it->second; | ||
} | ||
return rw_type; | ||
return RWType::INVALID; | ||
} | ||
|
||
void TransactionContext::RecordRead(const ItemPointer &location) { | ||
|
||
PELOTON_ASSERT(rw_set_.find(location) == rw_set_.end() || | ||
(rw_set_[location] != RWType::DELETE && | ||
rw_set_[location] != RWType::INS_DEL)); | ||
auto rw_set_it = rw_set_.find(location); | ||
if (rw_set_it != rw_set_.end()) { | ||
UNUSED_ATTRIBUTE RWType rw_type = rw_set_it->second; | ||
PELOTON_ASSERT(rw_type != RWType::DELETE && rw_type != RWType::INS_DEL); | ||
return; | ||
} | ||
rw_set_.insert(rw_set_it, std::make_pair(location, RWType::READ)); | ||
rw_set_[location] = RWType::READ; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So we have still two lookups here, one in line 99 and one in line 103. Is it even possible to do this with a single lookup? No, because some other thread could have changed the RW set between these to lines? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As best as I can tell, based on our current semantics we can't get away from two lookups on Read, or Delete. |
||
} | ||
|
||
void TransactionContext::RecordReadOwn(const ItemPointer &location) { | ||
auto rw_set_it = rw_set_.find(location); | ||
if (rw_set_it != rw_set_.end()) { | ||
RWType rw_type = rw_set_it->second; | ||
PELOTON_ASSERT(rw_type != RWType::DELETE && rw_type != RWType::INS_DEL); | ||
if (rw_type == RWType::READ) { | ||
rw_set_it->second = RWType::READ_OWN; | ||
} | ||
} else { | ||
rw_set_.insert(rw_set_it, std::make_pair(location, RWType::READ_OWN)); | ||
} | ||
PELOTON_ASSERT(rw_set_.find(location) == rw_set_.end() || | ||
(rw_set_[location] != RWType::DELETE && | ||
rw_set_[location] != RWType::INS_DEL)); | ||
rw_set_[location] = RWType::READ_OWN; | ||
} | ||
|
||
void TransactionContext::RecordUpdate(const ItemPointer &location) { | ||
PELOTON_ASSERT(rw_set_.find(location) == rw_set_.end() || | ||
(rw_set_[location] != RWType::DELETE && | ||
rw_set_[location] != RWType::INS_DEL)); | ||
auto rw_set_it = rw_set_.find(location); | ||
if (rw_set_it != rw_set_.end()) { | ||
RWType rw_type = rw_set_it->second; | ||
if (rw_type == RWType::READ || rw_type == RWType::READ_OWN) { | ||
is_written_ = true; | ||
if (rw_set_it->second == RWType::READ || rw_set_it->second == RWType::READ_OWN) { | ||
rw_set_it->second = RWType::UPDATE; | ||
} else if (rw_type == RWType::UPDATE || rw_type == RWType::INSERT) { | ||
return; | ||
} else { | ||
// DELETE or INS_DELETE | ||
PELOTON_ASSERT(false); | ||
} | ||
} else { | ||
rw_set_.insert(rw_set_it, std::make_pair(location, RWType::UPDATE)); | ||
return; | ||
} | ||
rw_set_[location] = RWType::UPDATE; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think some functionality got lost here. If There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You're right, I'll rearrange that logic. I was trying to get away from two lookups in the case of an insert but it won't allow that. |
||
} | ||
|
||
void TransactionContext::RecordInsert(const ItemPointer &location) { | ||
auto rw_set_it = rw_set_.find(location); | ||
if (rw_set_it != rw_set_.end()) { | ||
PELOTON_ASSERT(false); | ||
return; | ||
} | ||
rw_set_.insert(rw_set_it, std::make_pair(location, RWType::INSERT)); | ||
++insert_count_; | ||
PELOTON_ASSERT(rw_set_.find(location) == rw_set_.end()); | ||
rw_set_[location] = RWType::INSERT; | ||
} | ||
|
||
bool TransactionContext::RecordDelete(const ItemPointer &location) { | ||
PELOTON_ASSERT(rw_set_.find(location) == rw_set_.end() || | ||
(rw_set_[location] != RWType::DELETE && | ||
rw_set_[location] != RWType::INS_DEL)); | ||
auto rw_set_it = rw_set_.find(location); | ||
if (rw_set_it != rw_set_.end()) { | ||
RWType rw_type = rw_set_it->second; | ||
|
||
if (rw_type == RWType::READ || rw_type == RWType::READ_OWN) { | ||
rw_set_it->second = RWType::DELETE; | ||
is_written_ = true; | ||
return false; | ||
} else if (rw_type == RWType::UPDATE) { | ||
rw_set_it->second = RWType::DELETE; | ||
return false; | ||
} else if (rw_type == RWType::INSERT) { | ||
rw_set_it->second = RWType::INS_DEL; | ||
--insert_count_; | ||
return true; | ||
} else { | ||
// DELETE and INS_DEL | ||
PELOTON_ASSERT(false); | ||
return false; | ||
} | ||
if (rw_set_it != rw_set_.end() && rw_set_it->second == RWType::INSERT) { | ||
rw_set_it->second = RWType::INS_DEL; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am just wondering - what does happen, if the value of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I suspect it's a race that isn't handled in the current semantics of our RWSet. The hope is that we'll eventually get rid of the INS_DEL type anyway when we stop reusing tuple slots. |
||
return true; | ||
} else { | ||
rw_set_.insert(rw_set_it, std::make_pair(location, RWType::DELETE)); | ||
rw_set_[location] = RWType::DELETE; | ||
return false; | ||
} | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am a little unsure about removing the
is_written_
andinsert_count_
. These variables can be used to make Commits and Aborts faster. If you figure out that theis_written_
is false, you can take an entirely different code path and treat it like aREAD_ONLY
transaction.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's effectively what @lmwnshn is doing in #1402.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it is okay if we get rid of
insert_count_
but we should definitely useis_written_
. It will help with multi statement transactions that are not explicitly set to read only.