-
Notifications
You must be signed in to change notification settings - Fork 242
Fix optimistic locking under weak memory ordering #2581
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
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 | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -1294,6 +1294,12 @@ class btree_delete { | |||||||||
|
|
||||||||||
| // get next pointer | ||||||||||
| auto next = cur->getChild(idx); | ||||||||||
| if (next == nullptr) { | ||||||||||
| if (cur->lock.validate(cur_lease)) { | ||||||||||
| assert(false && "B-tree inner node has null child"); | ||||||||||
| } | ||||||||||
|
Comment on lines
+1298
to
+1300
Member
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. Maybe simplify these to
Suggested change
|
||||||||||
| return insert(k, hints); | ||||||||||
| } | ||||||||||
|
|
||||||||||
| // get lease on next level | ||||||||||
| auto next_lease = next->lock.start_read(); | ||||||||||
|
|
||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -444,7 +444,7 @@ class OptimisticReadWriteLock { | |
| bool validate(const Lease& lease) { | ||
| // check whether version number has changed in the mean-while | ||
| std::atomic_thread_fence(std::memory_order_acquire); | ||
| return lease.version == version.load(std::memory_order_relaxed); | ||
| return lease.version == version.load(std::memory_order_acquire); | ||
| } | ||
|
|
||
| /** | ||
|
|
@@ -466,14 +466,14 @@ class OptimisticReadWriteLock { | |
| detail::Waiter wait; | ||
|
|
||
| // set last bit => make it odd | ||
| auto v = version.fetch_or(0x1, std::memory_order_acquire); | ||
| auto v = version.fetch_or(0x1, std::memory_order_acq_rel); | ||
|
Member
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. Are the memory order changes necessary? They would have protected against the missing nullptr check in BTree, but that wasn't a problem with the lock itself. Adding the nullptr check is enough to avoid the crashes. I'm not entirely confident that I've understood the necessary ordering when we're doing optimistic writing, so I'm also fine with the change as it makes it easier to be clear on the order of the operations. |
||
|
|
||
| // check for concurrent writes | ||
| while ((v & 0x1) == 1) { | ||
| // wait for a moment | ||
| wait(); | ||
| // get an updated version | ||
| v = version.fetch_or(0x1, std::memory_order_acquire); | ||
| v = version.fetch_or(0x1, std::memory_order_acq_rel); | ||
| } | ||
|
|
||
| // done | ||
|
|
@@ -486,7 +486,7 @@ class OptimisticReadWriteLock { | |
| * @return true if write permission has been granted, false otherwise. | ||
| */ | ||
| bool try_start_write() { | ||
| auto v = version.fetch_or(0x1, std::memory_order_acquire); | ||
| auto v = version.fetch_or(0x1, std::memory_order_acq_rel); | ||
| return !(v & 0x1); | ||
| } | ||
|
|
||
|
|
@@ -499,7 +499,7 @@ class OptimisticReadWriteLock { | |
| * be granted, false otherwise. | ||
| */ | ||
| bool try_upgrade_to_write(const Lease& lease) { | ||
| auto v = version.fetch_or(0x1, std::memory_order_acquire); | ||
| auto v = version.fetch_or(0x1, std::memory_order_acq_rel); | ||
|
|
||
| // check whether write privileges have been gained | ||
| if (v & 0x1) return false; // there is another writer already | ||
|
|
@@ -539,7 +539,7 @@ class OptimisticReadWriteLock { | |
| * @return true if so, false otherwise | ||
| */ | ||
| bool is_write_locked() const { | ||
| return version & 0x1; | ||
| return version.load(std::memory_order_relaxed) & 0x1; | ||
| } | ||
| }; | ||
|
|
||
|
|
||
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 believe this method is not intended to be thread-safe. It is used when no write operations are in progress, or at least was intended to be. EqRel uses BTree out of the expected environment, and is not protecting it from modification.
I think it would be better to modify EqRel instead, and leave Btree.find() as is - not thread-safe, but fast. I explored this with mmcgr@47e8558
which seems to work.