-
Notifications
You must be signed in to change notification settings - Fork 9.8k
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
[3.5] etcdserver: backport check scheduledCompactKeyName and finishedCompac… #16068
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 |
---|---|---|
|
@@ -227,7 +227,27 @@ func (s *store) updateCompactRev(rev int64) (<-chan struct{}, int64, error) { | |
return nil, compactMainRev, nil | ||
} | ||
|
||
func (s *store) compact(trace *traceutil.Trace, rev, prevCompactRev int64) (<-chan struct{}, error) { | ||
// checkPrevCompactionCompleted checks whether the previous scheduled compaction is completed. | ||
func (s *store) checkPrevCompactionCompleted() bool { | ||
tx := s.b.ReadTx() | ||
tx.Lock() | ||
defer tx.Unlock() | ||
_, scheduledCompactBytes := tx.UnsafeRange(buckets.Meta, scheduledCompactKeyName, nil, 0) | ||
scheduledCompact := int64(0) | ||
if len(scheduledCompactBytes) != 0 { | ||
scheduledCompact = bytesToRev(scheduledCompactBytes[0]).main | ||
} | ||
|
||
_, finishedCompactBytes := tx.UnsafeRange(buckets.Meta, finishedCompactKeyName, nil, 0) | ||
finishedCompact := int64(0) | ||
if len(finishedCompactBytes) != 0 { | ||
finishedCompact = bytesToRev(finishedCompactBytes[0]).main | ||
|
||
} | ||
Comment on lines
+235
to
+246
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. Please add a The two functions should be reused in multiple places, (Please search It's accepted to fix it in a separate PR. Please also raise a followup ticket. |
||
return scheduledCompact == finishedCompact | ||
} | ||
|
||
func (s *store) compact(trace *traceutil.Trace, rev, prevCompactRev int64, prevCompactionCompleted bool) (<-chan struct{}, error) { | ||
ch := make(chan struct{}) | ||
var j = func(ctx context.Context) { | ||
if ctx.Err() != nil { | ||
|
@@ -240,7 +260,13 @@ func (s *store) compact(trace *traceutil.Trace, rev, prevCompactRev int64) (<-ch | |
s.compactBarrier(context.TODO(), ch) | ||
return | ||
} | ||
s.hashes.Store(hash) | ||
// Only store the hash value if the previous hash is completed, i.e. this compaction | ||
// hashes every revision from last compaction. For more details, see #15919. | ||
if prevCompactionCompleted { | ||
s.hashes.Store(hash) | ||
} else { | ||
s.lg.Info("previous compaction was interrupted, skip storing compaction hash value") | ||
} | ||
close(ch) | ||
} | ||
|
||
|
@@ -250,17 +276,19 @@ func (s *store) compact(trace *traceutil.Trace, rev, prevCompactRev int64) (<-ch | |
} | ||
|
||
func (s *store) compactLockfree(rev int64) (<-chan struct{}, error) { | ||
prevCompactionCompleted := s.checkPrevCompactionCompleted() | ||
ch, prevCompactRev, err := s.updateCompactRev(rev) | ||
if err != nil { | ||
return ch, err | ||
} | ||
|
||
return s.compact(traceutil.TODO(), rev, prevCompactRev) | ||
return s.compact(traceutil.TODO(), rev, prevCompactRev, prevCompactionCompleted) | ||
} | ||
|
||
func (s *store) Compact(trace *traceutil.Trace, rev int64) (<-chan struct{}, error) { | ||
s.mu.Lock() | ||
|
||
prevCompactionCompleted := s.checkPrevCompactionCompleted() | ||
ch, prevCompactRev, err := s.updateCompactRev(rev) | ||
trace.Step("check and update compact revision") | ||
if err != nil { | ||
|
@@ -269,7 +297,7 @@ func (s *store) Compact(trace *traceutil.Trace, rev int64) (<-chan struct{}, err | |
} | ||
s.mu.Unlock() | ||
|
||
return s.compact(trace, rev, prevCompactRev) | ||
return s.compact(trace, rev, prevCompactRev, prevCompactionCompleted) | ||
} | ||
|
||
func (s *store) Commit() { | ||
|
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.
Just curious why not use
tx.RLock()
but understand the PR is a backport of #15985There 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.
Lock()
forReadTx()
should be by default aRlock()
.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.
For my understanding, do you mean the following RWMutex
Lock
is equal toRLock
to protect the read buffer?etcd/server/storage/backend/read_tx.go
Lines 127 to 130 in 5e40a8b
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.
After investigating a little bit, I think you are right, we should use RLock() instead. Lock() should only be used when the read buffer is updated by the writes committed by the BatchTxs. However, there are several positions where use read-only operations but Lock() is used. I think it is good to open a separate PR to correct them all.
Please correct me if I'm wrong.
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.
Yep. That aligns with my understanding.
I also don't think it blocks this PR to be merged. This can be corrected separately.
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.
stricter lock
is true, it's alsowrong lock
. It's a bug to me.It should also have impact on performance for Non-K8s use case when auth is enabled. [Of course, it will be better if we have some performance comparison, but I will NOT force contributor to do it given it's a straightforward change]
That's why we need careful review. I wouldn't be afraid backporting it give it's a simple change and if we have confidence.
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.
Note I prefer to backporting it, but I am not insist on backporting it if there is strong objection from other maintainers.
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.
Without the change system behaves correctly, with the change only thing you get is performance improvement. How this is a bug?
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 would say it's harmless (on functionality) bug, obviously the lock isn't correctly be used. Let alone it has impact on performance.
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.
Bugs is when locks don't protect the critical section, relaxing locks is performance improvement. Nothing is harmless until proven, let alone concurrency change.