ZOOKEEPER-4689: Fix inaccessible node due to inconsistent ACL index after SNAP sync#1997
ZOOKEEPER-4689: Fix inaccessible node due to inconsistent ACL index after SNAP sync#1997adamyi wants to merge 2 commits into
Conversation
Please refer to JIRA for more details on the bug.
| /** | ||
| * checks if longval is cached (convertLong can convert it to ACLs). | ||
| * | ||
| * @param longVal |
There was a problem hiding this comment.
EmptyBlockTag: A block tag (@param, @return, @throws, @deprecated) has an empty description. Block tags without descriptions don't add much value for future readers of the code; consider removing the tag entirely or adding a description.
| * @param longVal | |
| * |
ℹ️ Expand to see all @sonatype-lift commands
You can reply with the following commands. For example, reply with @sonatype-lift ignoreall to leave out all findings.
| Command | Usage |
|---|---|
@sonatype-lift ignore |
Leave out the above finding from this PR |
@sonatype-lift ignoreall |
Leave out all the existing findings from this PR |
@sonatype-lift exclude <file|issue|path|tool> |
Exclude specified file|issue|path|tool from Lift findings by updating your config.toml file |
Note: When talking to LiftBot, you need to refresh the page to see its response.
Click here to add LiftBot to another repo.
Help us improve LIFT! (Sonatype LiftBot external survey)
Was this a good recommendation for you? Answering this survey will not impact your Lift settings.
[ 🙁 Not relevant ] - [ 😕 Won't fix ] - [ 😑 Not critical, will fix ] - [ 🙂 Critical, will fix ] - [ 😊 Critical, fixing now ]
| if (longVal == OPEN_UNSAFE_ACL_ID) { | ||
| return true; | ||
| } | ||
| return longKeyMap.containsKey(longVal); |
There was a problem hiding this comment.
THREAD_SAFETY_VIOLATION: Read/Write race. Non-private method ReferenceCountedACLCache.isLongCached(...) reads with synchronization from container this.longKeyMap via call to Map.containsKey(...). Potentially races with unsynchronized write in method ReferenceCountedACLCache.deserialize(...).
Reporting because this access may occur on a background thread.
ℹ️ Expand to see all @sonatype-lift commands
You can reply with the following commands. For example, reply with @sonatype-lift ignoreall to leave out all findings.
| Command | Usage |
|---|---|
@sonatype-lift ignore |
Leave out the above finding from this PR |
@sonatype-lift ignoreall |
Leave out all the existing findings from this PR |
@sonatype-lift exclude <file|issue|path|tool> |
Exclude specified file|issue|path|tool from Lift findings by updating your config.toml file |
Note: When talking to LiftBot, you need to refresh the page to see its response.
Click here to add LiftBot to another repo.
Help us improve LIFT! (Sonatype LiftBot external survey)
Was this a good recommendation for you? Answering this survey will not impact your Lift settings.
[ 🙁 Not relevant ] - [ 😕 Won't fix ] - [ 😑 Not critical, will fix ] - [ 🙂 Critical, will fix ] - [ 😊 Critical, fixing now ]
|
Unfortunately, there are some bugs with this patch: Bug 1Consider the following sequence of events:
We would create ACL 6 with a refcount of 1 at step 2 and leave it unchanged at step 3 because ACL 6 already exists. Deleting /a1 at step 4 would decrement the refcount and consequently garbage-collect the ACL entry, leaving /a2 pointing to a non-existent ACL entry. Bug 2Consider the following sequence of events:
When replaying, we would create ACL 6 at step 4; 7 at step 5. When replaying step 6, we would treat ACL 7 as already created with the value from step 5. That causes /a3 to have the ACL of /a2. This is wrong. FixesI'm proposing three approaches to fix these bugs. I don't feel strongly among these solutions and am happy to implement any of them. Do Zookeeper reviewers have a preference?
|
|
@kezhuw Do you mind taking a look or do you know who might be a more appropriate reviewer for this bug? Thanks :) |
There was a problem hiding this comment.
For your comments, I did not get what fixes#1 try to express. Both fixes#2 and fixes#3 are viable from my point of view, fixes#3 should be simple to go.
I wonder whether the alternative in jira is more appropriate:
Make aclIndex consistent upon re-deserialization (by either serializing it in snapshot or paying special attention to decrement it when removing cache)
This is easy to achieve if we retain topmost acl(a.k.a ACL aclIndex pointing to) in puring or removing.
aclIndex inconsistency itself is not a problem
Not sure, but concistency is a good.
who might be a more appropriate reviewer for this bug? Thanks :)
How about sending an email to dev mailing list ?
| parent.stat.setCversion(parentCVersion); | ||
| parent.stat.setPzxid(zxid); | ||
| } | ||
| Long acls = aclCache.convertAcls(acl); |
There was a problem hiding this comment.
Given this patch, how bug#1 could happen ?
We would create ACL 6 with a refcount of 1 at step 2 and leave it unchanged at step 3 because ACL 6 already exists. Deleting /a1 at step 4 would decrement the refcount and consequently garbage-collect the ACL entry, leaving /a2 pointing to a non-existent ACL entry.
step#3 creates a new node with existing ACL, so that ACL will get ref count incremented. step#4 will not delete ACL 6.
| // case, we'll replay node creation transaction. We | ||
| // should add it to cache and reset the ACL if the | ||
| // previous longval does not exist. | ||
| if (!aclCache.isLongCached(child.acl)) { |
There was a problem hiding this comment.
Is this the cause to bug#2 in this patch ?
|
For the record, we have also hit this in production. This is indeed a very critical issue, as the corruption can spread from member to member! I initially preferred solution 2 from the ticket description—the one which was tentatively implemented above—but given the difficulties encountered, and @kezhuw's suggestion of never removing the ACL We would also like to add some kind of (optional) "fsck" pass which sanity checks the tree before the service starts—to prevent this and other kinds of corruption from spreading—but that can be implemented in a followup ticket. Cc: @eolivelli, @symat, @anmolnar, in case you haven't seen this. |
|
Closed in favor of a newer version of the patch: #2425 |
Please refer to JIRA for details on the bug and why I chose to fix it this way.
An additional benefit of the patch is that we now no longer miscount refcount when replaying transactions. So we don't need to wait until next time we load snapshot to remove those unused ACL cache entries.