Skip to content

Commit 2b9833e

Browse files
committed
tests: Patch unique delete ops in robustness
Signed-off-by: Ashwani Kumar Kamal <[email protected]>
1 parent 2ce96db commit 2b9833e

File tree

2 files changed

+221
-67
lines changed

2 files changed

+221
-67
lines changed

tests/robustness/validate/patch_history.go

Lines changed: 173 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -24,37 +24,78 @@ import (
2424
"go.etcd.io/etcd/tests/v3/robustness/report"
2525
)
2626

27+
type patchArgs struct {
28+
returnTime int64
29+
clientCount int64
30+
persistedCount int64
31+
revision int64
32+
}
33+
2734
func patchLinearizableOperations(operations []porcupine.Operation, reports []report.ClientReport, persistedRequests []model.EtcdRequest) []porcupine.Operation {
28-
putRevision := putRevision(reports)
35+
putRevision, delRevision := watchRevisions(reports)
2936
persistedPutCount := countPersistedPuts(persistedRequests)
3037
clientPutCount := countClientPuts(reports)
31-
putReturnTime := uniquePutReturnTime(operations, persistedRequests, clientPutCount)
32-
return patchOperations(operations, putRevision, putReturnTime, clientPutCount, persistedPutCount)
38+
39+
persistedDeleteCount := countPersistedDeletes(persistedRequests)
40+
clientDeleteCount := countClientDeletes(reports)
41+
42+
putReturnTime, delReturnTime := uniqueOperationReturnTime(operations, persistedRequests, clientPutCount, clientDeleteCount)
43+
44+
putArgs := make(map[model.PutOptions]patchArgs)
45+
for opts, c := range clientPutCount {
46+
putArgs[opts] = patchArgs{
47+
clientCount: c,
48+
persistedCount: persistedPutCount[opts],
49+
returnTime: putReturnTime[opts],
50+
revision: putRevision[opts],
51+
}
52+
}
53+
delArgs := make(map[model.DeleteOptions]patchArgs)
54+
for opts, c := range clientDeleteCount {
55+
delArgs[opts] = patchArgs{
56+
clientCount: c,
57+
persistedCount: persistedDeleteCount[opts],
58+
returnTime: delReturnTime[opts],
59+
revision: delRevision[opts],
60+
}
61+
}
62+
63+
return patchOperations(
64+
operations, putArgs, delArgs,
65+
)
3366
}
3467

35-
func putRevision(reports []report.ClientReport) map[keyValue]int64 {
36-
requestRevision := map[keyValue]int64{}
68+
func watchRevisions(reports []report.ClientReport) (map[model.PutOptions]int64, map[model.DeleteOptions]int64) {
69+
putRevisions := map[model.PutOptions]int64{}
70+
delRevisions := map[model.DeleteOptions]int64{}
71+
3772
for _, client := range reports {
3873
for _, watch := range client.Watch {
3974
for _, resp := range watch.Responses {
4075
for _, event := range resp.Events {
4176
switch event.Type {
4277
case model.RangeOperation:
4378
case model.PutOperation:
44-
kv := keyValue{Key: event.Key, Value: event.Value}
45-
requestRevision[kv] = event.Revision
79+
kv := model.PutOptions{Key: event.Key, Value: event.Value}
80+
putRevisions[kv] = event.Revision
4681
case model.DeleteOperation:
82+
kv := model.DeleteOptions{Key: event.Key} // ADD: Track delete revisions
83+
delRevisions[kv] = event.Revision
4784
default:
4885
panic(fmt.Sprintf("unknown event type %q", event.Type))
4986
}
5087
}
5188
}
5289
}
5390
}
54-
return requestRevision
91+
return putRevisions, delRevisions
5592
}
5693

57-
func patchOperations(operations []porcupine.Operation, watchRevision, putReturnTime, clientPutCount, persistedPutCount map[keyValue]int64) []porcupine.Operation {
94+
func patchOperations(
95+
operations []porcupine.Operation,
96+
putArgs map[model.PutOptions]patchArgs,
97+
delArgs map[model.DeleteOptions]patchArgs,
98+
) []porcupine.Operation {
5899
newOperations := make([]porcupine.Operation, 0, len(operations))
59100

60101
for _, op := range operations {
@@ -70,26 +111,47 @@ func patchOperations(operations []porcupine.Operation, watchRevision, putReturnT
70111
for _, etcdOp := range append(request.Txn.OperationsOnSuccess, request.Txn.OperationsOnFailure...) {
71112
switch etcdOp.Type {
72113
case model.PutOperation:
73-
kv := keyValue{Key: etcdOp.Put.Key, Value: etcdOp.Put.Value}
74-
if _, ok := persistedPutCount[kv]; ok {
114+
kv := model.PutOptions{Key: etcdOp.Put.Key, Value: etcdOp.Put.Value}
115+
arg, ok := putArgs[kv]
116+
if !ok {
117+
continue
118+
}
119+
if arg.persistedCount > 0 {
75120
persisted = true
76121
}
77-
if count := clientPutCount[kv]; count != 1 {
122+
if arg.clientCount != 1 {
78123
continue
79124
}
80-
if revision, ok := watchRevision[kv]; ok {
81-
txnRevision = revision
125+
if arg.revision > 0 {
126+
txnRevision = arg.revision
82127
}
83-
if returnTime, ok := putReturnTime[kv]; ok {
84-
op.Return = min(op.Return, returnTime)
128+
if arg.returnTime > 0 {
129+
op.Return = min(op.Return, arg.returnTime)
85130
}
86131
case model.DeleteOperation:
132+
kv := model.DeleteOptions{Key: etcdOp.Delete.Key}
133+
arg, ok := delArgs[kv]
134+
if !ok {
135+
continue
136+
}
137+
if arg.persistedCount > 0 {
138+
persisted = true
139+
}
140+
if arg.clientCount != 1 {
141+
continue
142+
}
143+
if arg.revision > 0 {
144+
txnRevision = arg.revision
145+
}
146+
if arg.returnTime > 0 {
147+
op.Return = min(op.Return, arg.returnTime)
148+
}
87149
case model.RangeOperation:
88150
default:
89151
panic(fmt.Sprintf("unknown operation type %q", etcdOp.Type))
90152
}
91153
}
92-
if isUniqueTxn(request.Txn, clientPutCount) {
154+
if isUniqueTxn(request.Txn, putArgs, delArgs) {
93155
if !persisted {
94156
// Remove non persisted operations
95157
continue
@@ -106,12 +168,21 @@ func patchOperations(operations []porcupine.Operation, watchRevision, putReturnT
106168
return newOperations
107169
}
108170

109-
func isUniqueTxn(request *model.TxnRequest, clientRequestCount map[keyValue]int64) bool {
110-
return isUniqueOps(request.OperationsOnSuccess, clientRequestCount) && isUniqueOps(request.OperationsOnFailure, clientRequestCount)
171+
func containsDeleteOp(txn *model.TxnRequest) bool {
172+
for _, op := range append(txn.OperationsOnSuccess, txn.OperationsOnFailure...) {
173+
if op.Type == model.DeleteOperation {
174+
return true
175+
}
176+
}
177+
return false
178+
}
179+
180+
func isUniqueTxn(request *model.TxnRequest, putArgs map[model.PutOptions]patchArgs, delArgs map[model.DeleteOptions]patchArgs) bool {
181+
return isUniqueOps(request.OperationsOnSuccess, putArgs, delArgs) && isUniqueOps(request.OperationsOnFailure, putArgs, delArgs)
111182
}
112183

113-
func isUniqueOps(ops []model.EtcdOperation, clientRequestCount map[keyValue]int64) bool {
114-
return hasUniqueWriteOperation(ops, clientRequestCount) || !hasWriteOperation(ops)
184+
func isUniqueOps(ops []model.EtcdOperation, putArgs map[model.PutOptions]patchArgs, delArgs map[model.DeleteOptions]patchArgs) bool {
185+
return hasUniqueWriteOperation(ops, putArgs, delArgs) || !hasWriteOperation(ops)
115186
}
116187

117188
func hasWriteOperation(ops []model.EtcdOperation) bool {
@@ -123,15 +194,19 @@ func hasWriteOperation(ops []model.EtcdOperation) bool {
123194
return false
124195
}
125196

126-
func hasUniqueWriteOperation(ops []model.EtcdOperation, clientRequestCount map[keyValue]int64) bool {
197+
func hasUniqueWriteOperation(ops []model.EtcdOperation, putArgs map[model.PutOptions]patchArgs, delArgs map[model.DeleteOptions]patchArgs) bool {
127198
for _, operation := range ops {
128199
switch operation.Type {
129200
case model.PutOperation:
130-
kv := keyValue{Key: operation.Put.Key, Value: operation.Put.Value}
131-
if count := clientRequestCount[kv]; count == 1 {
201+
kv := model.PutOptions{Key: operation.Put.Key, Value: operation.Put.Value}
202+
if arg, ok := putArgs[kv]; ok && arg.clientCount == 1 {
132203
return true
133204
}
134205
case model.DeleteOperation:
206+
kv := model.DeleteOptions{Key: operation.Delete.Key}
207+
if arg, ok := delArgs[kv]; ok && arg.clientCount == 1 {
208+
return true
209+
}
135210
case model.RangeOperation:
136211
default:
137212
panic(fmt.Sprintf("unknown operation type %q", operation.Type))
@@ -140,25 +215,33 @@ func hasUniqueWriteOperation(ops []model.EtcdOperation, clientRequestCount map[k
140215
return false
141216
}
142217

143-
func uniquePutReturnTime(allOperations []porcupine.Operation, persistedRequests []model.EtcdRequest, clientPutCount map[keyValue]int64) map[keyValue]int64 {
144-
earliestReturnTime := map[keyValue]int64{}
218+
func uniqueOperationReturnTime(allOperations []porcupine.Operation, persistedRequests []model.EtcdRequest, clientPutCount map[model.PutOptions]int64, clientDeleteCount map[model.DeleteOptions]int64) (map[model.PutOptions]int64, map[model.DeleteOptions]int64) {
219+
putTimes := map[model.PutOptions]int64{}
220+
delTimes := map[model.DeleteOptions]int64{}
145221
var lastReturnTime int64
146222
for _, op := range allOperations {
147223
request := op.Input.(model.EtcdRequest)
148224
switch request.Type {
149225
case model.Txn:
150226
for _, etcdOp := range append(request.Txn.OperationsOnSuccess, request.Txn.OperationsOnFailure...) {
151-
if etcdOp.Type != model.PutOperation {
152-
continue
153-
}
154-
kv := keyValue{Key: etcdOp.Put.Key, Value: etcdOp.Put.Value}
155-
if count := clientPutCount[kv]; count > 1 {
156-
continue
157-
}
158-
if returnTime, ok := earliestReturnTime[kv]; !ok || returnTime > op.Return {
159-
earliestReturnTime[kv] = op.Return
227+
switch etcdOp.Type {
228+
case model.PutOperation:
229+
kv := model.PutOptions{Key: etcdOp.Put.Key, Value: etcdOp.Put.Value}
230+
if clientPutCount[kv] > 1 {
231+
continue
232+
}
233+
if returnTime, ok := putTimes[kv]; !ok || returnTime > op.Return {
234+
putTimes[kv] = op.Return
235+
}
236+
case model.DeleteOperation:
237+
kv := model.DeleteOptions{Key: etcdOp.Delete.Key}
238+
if clientDeleteCount[kv] > 1 {
239+
continue
240+
}
241+
if returnTime, ok := delTimes[kv]; !ok || returnTime > op.Return {
242+
delTimes[kv] = op.Return
243+
}
160244
}
161-
earliestReturnTime[kv] = op.Return
162245
}
163246
case model.Range:
164247
case model.LeaseGrant:
@@ -181,17 +264,25 @@ func uniquePutReturnTime(allOperations []porcupine.Operation, persistedRequests
181264
lastReturnTime--
182265
}
183266
for _, op := range request.Txn.OperationsOnSuccess {
184-
if op.Type != model.PutOperation {
185-
continue
186-
}
187-
kv := keyValue{Key: op.Put.Key, Value: op.Put.Value}
188-
if count := clientPutCount[kv]; count > 1 {
189-
continue
190-
}
191-
returnTime, ok := earliestReturnTime[kv]
192-
if ok {
193-
lastReturnTime = min(returnTime, lastReturnTime)
194-
earliestReturnTime[kv] = lastReturnTime
267+
switch op.Type {
268+
case model.PutOperation:
269+
kv := model.PutOptions{Key: op.Put.Key, Value: op.Put.Value}
270+
if clientPutCount[kv] > 1 {
271+
continue
272+
}
273+
if returnTime, ok := putTimes[kv]; ok {
274+
lastReturnTime = min(returnTime, lastReturnTime)
275+
putTimes[kv] = lastReturnTime
276+
}
277+
case model.DeleteOperation:
278+
kv := model.DeleteOptions{Key: op.Delete.Key}
279+
if clientDeleteCount[kv] > 1 {
280+
continue
281+
}
282+
if returnTime, ok := delTimes[kv]; ok {
283+
lastReturnTime = min(returnTime, lastReturnTime)
284+
delTimes[kv] = lastReturnTime
285+
}
195286
}
196287
}
197288
case model.LeaseGrant:
@@ -201,11 +292,11 @@ func uniquePutReturnTime(allOperations []porcupine.Operation, persistedRequests
201292
panic(fmt.Sprintf("Unknown request type: %q", request.Type))
202293
}
203294
}
204-
return earliestReturnTime
295+
return putTimes, delTimes
205296
}
206297

207-
func countClientPuts(reports []report.ClientReport) map[keyValue]int64 {
208-
counter := map[keyValue]int64{}
298+
func countClientPuts(reports []report.ClientReport) map[model.PutOptions]int64 {
299+
counter := map[model.PutOptions]int64{}
209300
for _, client := range reports {
210301
for _, op := range client.KeyValue {
211302
request := op.Input.(model.EtcdRequest)
@@ -215,21 +306,21 @@ func countClientPuts(reports []report.ClientReport) map[keyValue]int64 {
215306
return counter
216307
}
217308

218-
func countPersistedPuts(requests []model.EtcdRequest) map[keyValue]int64 {
219-
counter := map[keyValue]int64{}
309+
func countPersistedPuts(requests []model.EtcdRequest) map[model.PutOptions]int64 {
310+
counter := map[model.PutOptions]int64{}
220311
for _, request := range requests {
221312
countPuts(counter, request)
222313
}
223314
return counter
224315
}
225316

226-
func countPuts(counter map[keyValue]int64, request model.EtcdRequest) {
317+
func countPuts(counter map[model.PutOptions]int64, request model.EtcdRequest) {
227318
switch request.Type {
228319
case model.Txn:
229320
for _, operation := range append(request.Txn.OperationsOnSuccess, request.Txn.OperationsOnFailure...) {
230321
switch operation.Type {
231322
case model.PutOperation:
232-
kv := keyValue{Key: operation.Put.Key, Value: operation.Put.Value}
323+
kv := model.PutOptions{Key: operation.Put.Key, Value: operation.Put.Value}
233324
counter[kv]++
234325
case model.DeleteOperation:
235326
case model.RangeOperation:
@@ -247,7 +338,32 @@ func countPuts(counter map[keyValue]int64, request model.EtcdRequest) {
247338
}
248339
}
249340

250-
type keyValue struct {
251-
Key string
252-
Value model.ValueOrHash
341+
func countClientDeletes(reports []report.ClientReport) map[model.DeleteOptions]int64 {
342+
counter := map[model.DeleteOptions]int64{}
343+
for _, client := range reports {
344+
for _, op := range client.KeyValue {
345+
request := op.Input.(model.EtcdRequest)
346+
countDeletes(counter, request)
347+
}
348+
}
349+
return counter
350+
}
351+
352+
func countPersistedDeletes(requests []model.EtcdRequest) map[model.DeleteOptions]int64 {
353+
counter := map[model.DeleteOptions]int64{}
354+
for _, req := range requests {
355+
countDeletes(counter, req)
356+
}
357+
return counter
358+
}
359+
360+
func countDeletes(counter map[model.DeleteOptions]int64, request model.EtcdRequest) {
361+
if request.Type != model.Txn {
362+
return
363+
}
364+
for _, operation := range append(request.Txn.OperationsOnSuccess, request.Txn.OperationsOnFailure...) {
365+
if operation.Type == model.DeleteOperation {
366+
counter[operation.Delete]++
367+
}
368+
}
253369
}

0 commit comments

Comments
 (0)