mirror of
https://github.com/etcd-io/etcd.git
synced 2024-09-27 06:25:44 +00:00
tests: Extract history from client
Signed-off-by: Marek Siarkowicz <siarkowicz@google.com>
This commit is contained in:
parent
c5c2ea6aad
commit
45fdc2bbac
@ -18,20 +18,13 @@ import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/anishathalye/porcupine"
|
||||
clientv3 "go.etcd.io/etcd/client/v3"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
type recordingClient struct {
|
||||
client clientv3.Client
|
||||
|
||||
// id of the next write operation. If needed a new id might be requested from idProvider.
|
||||
id int
|
||||
idProvider idProvider
|
||||
|
||||
operations []porcupine.Operation
|
||||
failed []porcupine.Operation
|
||||
client clientv3.Client
|
||||
history *history
|
||||
}
|
||||
|
||||
func NewClient(endpoints []string, ids idProvider) (*recordingClient, error) {
|
||||
@ -45,11 +38,8 @@ func NewClient(endpoints []string, ids idProvider) (*recordingClient, error) {
|
||||
return nil, err
|
||||
}
|
||||
return &recordingClient{
|
||||
client: *cc,
|
||||
id: ids.ClientId(),
|
||||
idProvider: ids,
|
||||
operations: []porcupine.Operation{},
|
||||
failed: []porcupine.Operation{},
|
||||
client: *cc,
|
||||
history: NewHistory(ids),
|
||||
}, nil
|
||||
}
|
||||
|
||||
@ -64,17 +54,7 @@ func (c *recordingClient) Get(ctx context.Context, key string) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var readData string
|
||||
if len(resp.Kvs) == 1 {
|
||||
readData = string(resp.Kvs[0].Value)
|
||||
}
|
||||
c.operations = append(c.operations, porcupine.Operation{
|
||||
ClientId: c.id,
|
||||
Input: EtcdRequest{Op: Get, Key: key},
|
||||
Call: callTime.UnixNano(),
|
||||
Output: EtcdResponse{GetData: readData, Revision: resp.Header.Revision},
|
||||
Return: returnTime.UnixNano(),
|
||||
})
|
||||
c.history.AppendGet(key, callTime, returnTime, resp)
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -82,81 +62,14 @@ func (c *recordingClient) Put(ctx context.Context, key, value string) error {
|
||||
callTime := time.Now()
|
||||
resp, err := c.client.Put(ctx, key, value)
|
||||
returnTime := time.Now()
|
||||
if err != nil {
|
||||
c.failed = append(c.failed, porcupine.Operation{
|
||||
ClientId: c.id,
|
||||
Input: EtcdRequest{Op: Put, Key: key, PutData: value},
|
||||
Call: callTime.UnixNano(),
|
||||
Output: EtcdResponse{Err: err},
|
||||
Return: 0, // For failed writes we don't know when request has really finished.
|
||||
})
|
||||
// Operations of single client needs to be sequential.
|
||||
// As we don't know return time of failed operations, all new writes need to be done with new client id.
|
||||
c.id = c.idProvider.ClientId()
|
||||
return err
|
||||
}
|
||||
var revision int64
|
||||
if resp != nil && resp.Header != nil {
|
||||
revision = resp.Header.Revision
|
||||
}
|
||||
c.operations = append(c.operations, porcupine.Operation{
|
||||
ClientId: c.id,
|
||||
Input: EtcdRequest{Op: Put, Key: key, PutData: value},
|
||||
Call: callTime.UnixNano(),
|
||||
Output: EtcdResponse{Err: err, Revision: revision},
|
||||
Return: returnTime.UnixNano(),
|
||||
})
|
||||
return nil
|
||||
c.history.AppendPut(key, value, callTime, returnTime, resp, err)
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *recordingClient) Delete(ctx context.Context, key string) error {
|
||||
callTime := time.Now()
|
||||
resp, err := c.client.Delete(ctx, key)
|
||||
returnTime := time.Now()
|
||||
if err != nil {
|
||||
c.failed = append(c.failed, porcupine.Operation{
|
||||
ClientId: c.id,
|
||||
Input: EtcdRequest{Op: Delete, Key: key},
|
||||
Call: callTime.UnixNano(),
|
||||
Output: EtcdResponse{Err: err},
|
||||
Return: 0, // For failed writes we don't know when request has really finished.
|
||||
})
|
||||
// Operations of single client needs to be sequential.
|
||||
// As we don't know return time of failed operations, all new writes need to be done with new client id.
|
||||
c.id = c.idProvider.ClientId()
|
||||
return err
|
||||
}
|
||||
var revision int64
|
||||
var deleted int64
|
||||
if resp != nil && resp.Header != nil {
|
||||
revision = resp.Header.Revision
|
||||
deleted = resp.Deleted
|
||||
}
|
||||
c.operations = append(c.operations, porcupine.Operation{
|
||||
ClientId: c.id,
|
||||
Input: EtcdRequest{Op: Delete, Key: key},
|
||||
Call: callTime.UnixNano(),
|
||||
Output: EtcdResponse{Revision: revision, Deleted: deleted, Err: err},
|
||||
Return: returnTime.UnixNano(),
|
||||
})
|
||||
c.history.AppendDelete(key, callTime, returnTime, resp, err)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *recordingClient) Operations() []porcupine.Operation {
|
||||
operations := make([]porcupine.Operation, 0, len(c.operations)+len(c.failed))
|
||||
var maxTime int64
|
||||
for _, op := range c.operations {
|
||||
operations = append(operations, op)
|
||||
if op.Return > maxTime {
|
||||
maxTime = op.Return
|
||||
}
|
||||
}
|
||||
for _, op := range c.failed {
|
||||
if op.Call > maxTime {
|
||||
continue
|
||||
}
|
||||
op.Return = maxTime + 1
|
||||
operations = append(operations, op)
|
||||
}
|
||||
return operations
|
||||
}
|
||||
|
129
tests/linearizability/history.go
Normal file
129
tests/linearizability/history.go
Normal file
@ -0,0 +1,129 @@
|
||||
// Copyright 2022 The etcd Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package linearizability
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/anishathalye/porcupine"
|
||||
clientv3 "go.etcd.io/etcd/client/v3"
|
||||
)
|
||||
|
||||
type history struct {
|
||||
// id of the next write operation. If needed a new id might be requested from idProvider.
|
||||
id int
|
||||
idProvider idProvider
|
||||
|
||||
operations []porcupine.Operation
|
||||
failed []porcupine.Operation
|
||||
}
|
||||
|
||||
func NewHistory(ids idProvider) *history {
|
||||
return &history{
|
||||
id: ids.ClientId(),
|
||||
idProvider: ids,
|
||||
operations: []porcupine.Operation{},
|
||||
failed: []porcupine.Operation{},
|
||||
}
|
||||
}
|
||||
|
||||
func (h *history) AppendGet(key string, start, end time.Time, resp *clientv3.GetResponse) {
|
||||
var readData string
|
||||
if len(resp.Kvs) == 1 {
|
||||
readData = string(resp.Kvs[0].Value)
|
||||
}
|
||||
h.operations = append(h.operations, porcupine.Operation{
|
||||
ClientId: h.id,
|
||||
Input: EtcdRequest{Op: Get, Key: key},
|
||||
Call: start.UnixNano(),
|
||||
Output: EtcdResponse{GetData: readData, Revision: resp.Header.Revision},
|
||||
Return: end.UnixNano(),
|
||||
})
|
||||
}
|
||||
|
||||
func (h *history) AppendPut(key, value string, start, end time.Time, resp *clientv3.PutResponse, err error) {
|
||||
if err != nil {
|
||||
h.failed = append(h.failed, porcupine.Operation{
|
||||
ClientId: h.id,
|
||||
Input: EtcdRequest{Op: Put, Key: key, PutData: value},
|
||||
Call: start.UnixNano(),
|
||||
Output: EtcdResponse{Err: err},
|
||||
Return: 0, // For failed writes we don't know when request has really finished.
|
||||
})
|
||||
// Operations of single client needs to be sequential.
|
||||
// As we don't know return time of failed operations, all new writes need to be done with new client id.
|
||||
h.id = h.idProvider.ClientId()
|
||||
return
|
||||
}
|
||||
var revision int64
|
||||
if resp != nil && resp.Header != nil {
|
||||
revision = resp.Header.Revision
|
||||
}
|
||||
h.operations = append(h.operations, porcupine.Operation{
|
||||
ClientId: h.id,
|
||||
Input: EtcdRequest{Op: Put, Key: key, PutData: value},
|
||||
Call: start.UnixNano(),
|
||||
Output: EtcdResponse{Err: err, Revision: revision},
|
||||
Return: end.UnixNano(),
|
||||
})
|
||||
}
|
||||
|
||||
func (h *history) AppendDelete(key string, start, end time.Time, resp *clientv3.DeleteResponse, err error) {
|
||||
if err != nil {
|
||||
h.failed = append(h.failed, porcupine.Operation{
|
||||
ClientId: h.id,
|
||||
Input: EtcdRequest{Op: Delete, Key: key},
|
||||
Call: start.UnixNano(),
|
||||
Output: EtcdResponse{Err: err},
|
||||
Return: 0, // For failed writes we don't know when request has really finished.
|
||||
})
|
||||
// Operations of single client needs to be sequential.
|
||||
// As we don't know return time of failed operations, all new writes need to be done with new client id.
|
||||
h.id = h.idProvider.ClientId()
|
||||
return
|
||||
}
|
||||
var revision int64
|
||||
var deleted int64
|
||||
if resp != nil && resp.Header != nil {
|
||||
revision = resp.Header.Revision
|
||||
deleted = resp.Deleted
|
||||
}
|
||||
h.operations = append(h.operations, porcupine.Operation{
|
||||
ClientId: h.id,
|
||||
Input: EtcdRequest{Op: Delete, Key: key},
|
||||
Call: start.UnixNano(),
|
||||
Output: EtcdResponse{Revision: revision, Deleted: deleted, Err: err},
|
||||
Return: end.UnixNano(),
|
||||
})
|
||||
}
|
||||
|
||||
func (h *history) Operations() []porcupine.Operation {
|
||||
operations := make([]porcupine.Operation, 0, len(h.operations)+len(h.failed))
|
||||
var maxTime int64
|
||||
for _, op := range h.operations {
|
||||
operations = append(operations, op)
|
||||
if op.Return > maxTime {
|
||||
maxTime = op.Return
|
||||
}
|
||||
}
|
||||
for _, op := range h.failed {
|
||||
if op.Call > maxTime {
|
||||
continue
|
||||
}
|
||||
op.Return = maxTime + 1
|
||||
operations = append(operations, op)
|
||||
}
|
||||
return operations
|
||||
}
|
@ -162,7 +162,7 @@ func simulateTraffic(ctx context.Context, t *testing.T, clus *e2e.EtcdProcessClu
|
||||
|
||||
config.traffic.Run(ctx, c, limiter, ids)
|
||||
mux.Lock()
|
||||
operations = append(operations, c.Operations()...)
|
||||
operations = append(operations, c.history.Operations()...)
|
||||
mux.Unlock()
|
||||
}(c)
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user