Skip to content

Commit 8e48a51

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

File tree

1 file changed

+160
-51
lines changed

1 file changed

+160
-51
lines changed

tests/robustness/validate/patch_history.go

Lines changed: 160 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -24,24 +24,54 @@ 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+
}
32+
2733
func patchLinearizableOperations(operations []porcupine.Operation, reports []report.ClientReport, persistedRequests []model.EtcdRequest) []porcupine.Operation {
2834
putRevision := putRevision(reports)
2935
persistedPutCount := countPersistedPuts(persistedRequests)
3036
clientPutCount := countClientPuts(reports)
31-
putReturnTime := uniquePutReturnTime(operations, persistedRequests, clientPutCount)
32-
return patchOperations(operations, putRevision, putReturnTime, clientPutCount, persistedPutCount)
37+
38+
persistedDeleteCount := countPersistedDeletes(persistedRequests)
39+
clientDeleteCount := countClientDeletes(reports)
40+
41+
putReturnTime, delReturnTime := uniqueOperationReturnTime(operations, persistedRequests, clientPutCount, clientDeleteCount)
42+
43+
putArgs := make(map[model.PutOptions]patchArgs)
44+
for opts, c := range clientPutCount {
45+
putArgs[opts] = patchArgs{
46+
clientCount: c,
47+
persistedCount: persistedPutCount[opts],
48+
returnTime: putReturnTime[opts],
49+
}
50+
}
51+
delArgs := make(map[model.DeleteOptions]patchArgs)
52+
for opts, c := range clientDeleteCount {
53+
delArgs[opts] = patchArgs{
54+
clientCount: c,
55+
persistedCount: persistedDeleteCount[opts],
56+
returnTime: delReturnTime[opts],
57+
}
58+
}
59+
60+
return patchOperations(
61+
operations, putRevision, putArgs, delArgs,
62+
)
3363
}
3464

35-
func putRevision(reports []report.ClientReport) map[keyValue]int64 {
36-
requestRevision := map[keyValue]int64{}
65+
func putRevision(reports []report.ClientReport) map[model.PutOptions]int64 {
66+
requestRevision := map[model.PutOptions]int64{}
3767
for _, client := range reports {
3868
for _, watch := range client.Watch {
3969
for _, resp := range watch.Responses {
4070
for _, event := range resp.Events {
4171
switch event.Type {
4272
case model.RangeOperation:
4373
case model.PutOperation:
44-
kv := keyValue{Key: event.Key, Value: event.Value}
74+
kv := model.PutOptions{Key: event.Key, Value: event.Value}
4575
requestRevision[kv] = event.Revision
4676
case model.DeleteOperation:
4777
default:
@@ -54,7 +84,12 @@ func putRevision(reports []report.ClientReport) map[keyValue]int64 {
5484
return requestRevision
5585
}
5686

57-
func patchOperations(operations []porcupine.Operation, watchRevision, putReturnTime, clientPutCount, persistedPutCount map[keyValue]int64) []porcupine.Operation {
87+
func patchOperations(
88+
operations []porcupine.Operation,
89+
putRevision map[model.PutOptions]int64,
90+
putArgs map[model.PutOptions]patchArgs,
91+
delArgs map[model.DeleteOptions]patchArgs,
92+
) []porcupine.Operation {
5893
newOperations := make([]porcupine.Operation, 0, len(operations))
5994

6095
for _, op := range operations {
@@ -70,26 +105,39 @@ func patchOperations(operations []porcupine.Operation, watchRevision, putReturnT
70105
for _, etcdOp := range append(request.Txn.OperationsOnSuccess, request.Txn.OperationsOnFailure...) {
71106
switch etcdOp.Type {
72107
case model.PutOperation:
73-
kv := keyValue{Key: etcdOp.Put.Key, Value: etcdOp.Put.Value}
74-
if _, ok := persistedPutCount[kv]; ok {
108+
kv := model.PutOptions{Key: etcdOp.Put.Key, Value: etcdOp.Put.Value}
109+
arg, ok := putArgs[kv]
110+
if ok {
75111
persisted = true
76112
}
77-
if count := clientPutCount[kv]; count != 1 {
113+
if arg.clientCount != 1 {
78114
continue
79115
}
80-
if revision, ok := watchRevision[kv]; ok {
116+
if revision, ok := putRevision[kv]; ok {
81117
txnRevision = revision
82118
}
83-
if returnTime, ok := putReturnTime[kv]; ok {
84-
op.Return = min(op.Return, returnTime)
85-
}
119+
op.Return = min(op.Return, arg.returnTime)
86120
case model.DeleteOperation:
121+
key := model.DeleteOptions{Key: etcdOp.Delete.Key}
122+
arg, ok := delArgs[key]
123+
if !ok {
124+
continue
125+
}
126+
if arg.persistedCount > 0 {
127+
persisted = true
128+
}
129+
if arg.clientCount != 1 {
130+
continue
131+
}
132+
if arg.returnTime > 0 {
133+
op.Return = min(op.Return, arg.returnTime)
134+
}
87135
case model.RangeOperation:
88136
default:
89137
panic(fmt.Sprintf("unknown operation type %q", etcdOp.Type))
90138
}
91139
}
92-
if isUniqueTxn(request.Txn, clientPutCount) {
140+
if isUniqueTxn(request.Txn, putArgs, delArgs) {
93141
if !persisted {
94142
// Remove non persisted operations
95143
continue
@@ -106,12 +154,21 @@ func patchOperations(operations []porcupine.Operation, watchRevision, putReturnT
106154
return newOperations
107155
}
108156

109-
func isUniqueTxn(request *model.TxnRequest, clientRequestCount map[keyValue]int64) bool {
110-
return isUniqueOps(request.OperationsOnSuccess, clientRequestCount) && isUniqueOps(request.OperationsOnFailure, clientRequestCount)
157+
func containsDeleteOp(txn *model.TxnRequest) bool {
158+
for _, op := range append(txn.OperationsOnSuccess, txn.OperationsOnFailure...) {
159+
if op.Type == model.DeleteOperation {
160+
return true
161+
}
162+
}
163+
return false
111164
}
112165

113-
func isUniqueOps(ops []model.EtcdOperation, clientRequestCount map[keyValue]int64) bool {
114-
return hasUniqueWriteOperation(ops, clientRequestCount) || !hasWriteOperation(ops)
166+
func isUniqueTxn(request *model.TxnRequest, putArgs map[model.PutOptions]patchArgs, delArgs map[model.DeleteOptions]patchArgs) bool {
167+
return isUniqueOps(request.OperationsOnSuccess, putArgs, delArgs) && isUniqueOps(request.OperationsOnFailure, putArgs, delArgs)
168+
}
169+
170+
func isUniqueOps(ops []model.EtcdOperation, putArgs map[model.PutOptions]patchArgs, delArgs map[model.DeleteOptions]patchArgs) bool {
171+
return hasUniqueWriteOperation(ops, putArgs, delArgs) || !hasWriteOperation(ops)
115172
}
116173

117174
func hasWriteOperation(ops []model.EtcdOperation) bool {
@@ -123,15 +180,19 @@ func hasWriteOperation(ops []model.EtcdOperation) bool {
123180
return false
124181
}
125182

126-
func hasUniqueWriteOperation(ops []model.EtcdOperation, clientRequestCount map[keyValue]int64) bool {
183+
func hasUniqueWriteOperation(ops []model.EtcdOperation, putArgs map[model.PutOptions]patchArgs, delArgs map[model.DeleteOptions]patchArgs) bool {
127184
for _, operation := range ops {
128185
switch operation.Type {
129186
case model.PutOperation:
130-
kv := keyValue{Key: operation.Put.Key, Value: operation.Put.Value}
131-
if count := clientRequestCount[kv]; count == 1 {
187+
kv := model.PutOptions{Key: operation.Put.Key, Value: operation.Put.Value}
188+
if arg, ok := putArgs[kv]; ok && arg.clientCount == 1 {
132189
return true
133190
}
134191
case model.DeleteOperation:
192+
kv := model.DeleteOptions{Key: operation.Delete.Key}
193+
if arg, ok := delArgs[kv]; ok && arg.clientCount == 1 {
194+
return true
195+
}
135196
case model.RangeOperation:
136197
default:
137198
panic(fmt.Sprintf("unknown operation type %q", operation.Type))
@@ -140,25 +201,35 @@ func hasUniqueWriteOperation(ops []model.EtcdOperation, clientRequestCount map[k
140201
return false
141202
}
142203

143-
func uniquePutReturnTime(allOperations []porcupine.Operation, persistedRequests []model.EtcdRequest, clientPutCount map[keyValue]int64) map[keyValue]int64 {
144-
earliestReturnTime := map[keyValue]int64{}
204+
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) {
205+
putTimes := map[model.PutOptions]int64{}
206+
delTimes := map[model.DeleteOptions]int64{}
145207
var lastReturnTime int64
146208
for _, op := range allOperations {
147209
request := op.Input.(model.EtcdRequest)
148210
switch request.Type {
149211
case model.Txn:
150212
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
213+
switch etcdOp.Type {
214+
case model.PutOperation:
215+
kv := model.PutOptions{Key: etcdOp.Put.Key, Value: etcdOp.Put.Value}
216+
if clientPutCount[kv] > 1 {
217+
continue
218+
}
219+
if returnTime, ok := putTimes[kv]; !ok || returnTime > op.Return {
220+
putTimes[kv] = op.Return
221+
}
222+
putTimes[kv] = op.Return
223+
case model.DeleteOperation:
224+
kv := model.DeleteOptions{Key: etcdOp.Delete.Key}
225+
if clientDeleteCount[kv] > 1 {
226+
continue
227+
}
228+
if returnTime, ok := delTimes[kv]; !ok || returnTime > op.Return {
229+
delTimes[kv] = op.Return
230+
}
231+
delTimes[kv] = op.Return
160232
}
161-
earliestReturnTime[kv] = op.Return
162233
}
163234
case model.Range:
164235
case model.LeaseGrant:
@@ -181,17 +252,25 @@ func uniquePutReturnTime(allOperations []porcupine.Operation, persistedRequests
181252
lastReturnTime--
182253
}
183254
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
255+
switch op.Type {
256+
case model.PutOperation:
257+
kv := model.PutOptions{Key: op.Put.Key, Value: op.Put.Value}
258+
if clientPutCount[kv] > 1 {
259+
continue
260+
}
261+
if returnTime, ok := putTimes[kv]; ok {
262+
lastReturnTime = min(returnTime, lastReturnTime)
263+
putTimes[kv] = lastReturnTime
264+
}
265+
case model.DeleteOperation:
266+
kv := model.DeleteOptions{Key: op.Delete.Key}
267+
if clientDeleteCount[kv] > 1 {
268+
continue
269+
}
270+
if returnTime, ok := delTimes[kv]; ok {
271+
lastReturnTime = min(returnTime, lastReturnTime)
272+
delTimes[kv] = lastReturnTime
273+
}
195274
}
196275
}
197276
case model.LeaseGrant:
@@ -201,11 +280,11 @@ func uniquePutReturnTime(allOperations []porcupine.Operation, persistedRequests
201280
panic(fmt.Sprintf("Unknown request type: %q", request.Type))
202281
}
203282
}
204-
return earliestReturnTime
283+
return putTimes, delTimes
205284
}
206285

207-
func countClientPuts(reports []report.ClientReport) map[keyValue]int64 {
208-
counter := map[keyValue]int64{}
286+
func countClientPuts(reports []report.ClientReport) map[model.PutOptions]int64 {
287+
counter := map[model.PutOptions]int64{}
209288
for _, client := range reports {
210289
for _, op := range client.KeyValue {
211290
request := op.Input.(model.EtcdRequest)
@@ -215,21 +294,21 @@ func countClientPuts(reports []report.ClientReport) map[keyValue]int64 {
215294
return counter
216295
}
217296

218-
func countPersistedPuts(requests []model.EtcdRequest) map[keyValue]int64 {
219-
counter := map[keyValue]int64{}
297+
func countPersistedPuts(requests []model.EtcdRequest) map[model.PutOptions]int64 {
298+
counter := map[model.PutOptions]int64{}
220299
for _, request := range requests {
221300
countPuts(counter, request)
222301
}
223302
return counter
224303
}
225304

226-
func countPuts(counter map[keyValue]int64, request model.EtcdRequest) {
305+
func countPuts(counter map[model.PutOptions]int64, request model.EtcdRequest) {
227306
switch request.Type {
228307
case model.Txn:
229308
for _, operation := range append(request.Txn.OperationsOnSuccess, request.Txn.OperationsOnFailure...) {
230309
switch operation.Type {
231310
case model.PutOperation:
232-
kv := keyValue{Key: operation.Put.Key, Value: operation.Put.Value}
311+
kv := model.PutOptions{Key: operation.Put.Key, Value: operation.Put.Value}
233312
counter[kv]++
234313
case model.DeleteOperation:
235314
case model.RangeOperation:
@@ -247,6 +326,36 @@ func countPuts(counter map[keyValue]int64, request model.EtcdRequest) {
247326
}
248327
}
249328

329+
func countClientDeletes(reports []report.ClientReport) map[model.DeleteOptions]int64 {
330+
counter := map[model.DeleteOptions]int64{}
331+
for _, client := range reports {
332+
for _, op := range client.KeyValue {
333+
request := op.Input.(model.EtcdRequest)
334+
countDeletes(counter, request)
335+
}
336+
}
337+
return counter
338+
}
339+
340+
func countPersistedDeletes(requests []model.EtcdRequest) map[model.DeleteOptions]int64 {
341+
counter := map[model.DeleteOptions]int64{}
342+
for _, req := range requests {
343+
countDeletes(counter, req)
344+
}
345+
return counter
346+
}
347+
348+
func countDeletes(counter map[model.DeleteOptions]int64, request model.EtcdRequest) {
349+
if request.Type != model.Txn {
350+
return
351+
}
352+
for _, operation := range append(request.Txn.OperationsOnSuccess, request.Txn.OperationsOnFailure...) {
353+
if operation.Type == model.DeleteOperation {
354+
counter[operation.Delete]++
355+
}
356+
}
357+
}
358+
250359
type keyValue struct {
251360
Key string
252361
Value model.ValueOrHash

0 commit comments

Comments
 (0)