From b34c64f759c9718038b754187f7b7d1daaa47df7 Mon Sep 17 00:00:00 2001 From: Harsh Rawat Date: Tue, 14 Jan 2025 01:38:22 +0530 Subject: [PATCH] added the ttrpc stress utility This change adds a stress utility which can be used for stress testing the ttrpc connection. This tool represents a simple client-server interaction where the client sends continuous requests to the server, and the server responds with the same data, allowing for testing of concurrent request handling and response verification. This tool is adapted from https://github.com/kevpar/ttrpcstress.git which was written by Kevin Parsons. Signed-off-by: Harsh Rawat --- Makefile | 2 +- cmd/ttrpc-stress/README.md | 62 ++++++++ cmd/ttrpc-stress/connection_other.go | 32 ++++ cmd/ttrpc-stress/connection_windows.go | 41 +++++ cmd/ttrpc-stress/main.go | 203 +++++++++++++++++++++++++ cmd/ttrpc-stress/payload/doc.go | 17 +++ cmd/ttrpc-stress/payload/payload.pb.go | 162 ++++++++++++++++++++ cmd/ttrpc-stress/payload/payload.proto | 25 +++ go.mod | 2 + go.sum | 4 + 10 files changed, 549 insertions(+), 1 deletion(-) create mode 100644 cmd/ttrpc-stress/README.md create mode 100644 cmd/ttrpc-stress/connection_other.go create mode 100644 cmd/ttrpc-stress/connection_windows.go create mode 100644 cmd/ttrpc-stress/main.go create mode 100644 cmd/ttrpc-stress/payload/doc.go create mode 100644 cmd/ttrpc-stress/payload/payload.pb.go create mode 100644 cmd/ttrpc-stress/payload/payload.proto diff --git a/Makefile b/Makefile index c3a497dca..b0eed6967 100644 --- a/Makefile +++ b/Makefile @@ -24,7 +24,7 @@ WHALE = "🇩" ONI = "👹" # Project binaries. -COMMANDS=protoc-gen-go-ttrpc protoc-gen-gogottrpc +COMMANDS=protoc-gen-go-ttrpc protoc-gen-gogottrpc ttrpc-stress ifdef BUILDTAGS GO_BUILDTAGS = ${BUILDTAGS} diff --git a/cmd/ttrpc-stress/README.md b/cmd/ttrpc-stress/README.md new file mode 100644 index 000000000..aa93fb9e1 --- /dev/null +++ b/cmd/ttrpc-stress/README.md @@ -0,0 +1,62 @@ +# ttrpc-stress + +This is a simple client/server utility designed to stress-test a TTRPC connection. It aims to identify potential deadlock cases during repeated, rapid TTRPC requests. + +## Overview of the tool + +- The **server** listens for connections and exposes a single, straightforward method. It responds immediately to any requests. +- The **client** creates multiple worker goroutines that send a large number of requests to the server as quickly as possible. + +This tool represents a simple client-server interaction where the client sends requests to the server, and the server responds with the same data, allowing for testing of concurrent request handling and response verification. By utilizing core TTRPC facilities like `ttrpc.(*Client).Call` and `ttrpc.(*Server).Register` instead of generated client/server code, the test remains straightforward and effective. + +## Usage + +The `ttrpc-stress` command provides two modes of operation: server and client. + +### Run the Server + +To start the server, specify a Unix socket or named pipe as the address: +```bash +ttrpc-stress server +``` +- ``: The Unix socket or named pipe to listen on. + +### Run the Client + +To start the client, specify the address, number of iterations, and number of workers: +```bash +ttrpc-stress client +``` +- ``: The Unix socket or named pipe to connect to. +- ``: The total number of iterations to execute. +- ``: The number of workers handling the iterations. + +## Version Compatibility Testing + +One of the primary motivations for developing this stress utility was to identify potential deadlock scenarios when using different versions of the server and client. The goal is to test the current version of TTRPC, which is used to build `ttrpc-stress`, against the following older versions in both server and client scenarios: + +- `v1.0.2` +- `v1.1.0` +- `v1.2.0` +- `v1.2.4` +- `latest` + +### Known Issues in TTRPC Versions + +| Version Range | Description | Comments | +|---------------------|-------------------------------------------|------------------------------------------------------------------| +| **v1.0.2 and before** | Original deadlock bug | [#94](https://github.com/containerd/ttrpc/pull/94) for fixing deadlock in `v1.1.0` | +| **v1.1.0 - v1.2.0** | No known deadlock bugs | | +| **v1.2.0 - v1.2.4** | Streaming with a new deadlock bug | [#107](https://github.com/containerd/ttrpc/pull/107) introduced deadlock in `v1.2.0` | +| **After v1.2.4** | No known deadlock bugs | [#168](https://github.com/containerd/ttrpc/pull/168) for fixing deadlock in `v1.2.4` | +--- + +Clients before `v1.1.0` and between `v1.2.0`-`v1.2.3` can encounted the deadlock. + +However, if the **server** version is `v1.2.0` or later, deadlock issues in the client may be avoided. + +Please refer to https://github.com/containerd/ttrpc/issues/72 for more information about the deadlock bug. + +--- + +Happy testing! diff --git a/cmd/ttrpc-stress/connection_other.go b/cmd/ttrpc-stress/connection_other.go new file mode 100644 index 000000000..4e0bd65c6 --- /dev/null +++ b/cmd/ttrpc-stress/connection_other.go @@ -0,0 +1,32 @@ +//go:build !windows +// +build !windows + +/* + Copyright The containerd 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 main + +import "net" + +// listenConnection listens for incoming Unix domain socket connections at the specified address. +func listenConnection(addr string) (net.Listener, error) { + return net.Listen("unix", addr) +} + +// dialConnection dials a Unix domain socket connection to the specified address. +func dialConnection(addr string) (net.Conn, error) { + return net.Dial("unix", addr) +} diff --git a/cmd/ttrpc-stress/connection_windows.go b/cmd/ttrpc-stress/connection_windows.go new file mode 100644 index 000000000..0a31fe76d --- /dev/null +++ b/cmd/ttrpc-stress/connection_windows.go @@ -0,0 +1,41 @@ +//go:build windows +// +build windows + +/* + Copyright The containerd 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 main + +import ( + "net" + + "github.com/Microsoft/go-winio" +) + +// listenConnection listens for incoming named pipe connections at the specified address. +func listenConnection(addr string) (net.Listener, error) { + return winio.ListenPipe(addr, &winio.PipeConfig{ + // 0 buffer sizes for pipe is important to help deadlock to occur. + // It can still occur if there is buffering, but it takes more IO volume to hit it. + InputBufferSize: 0, + OutputBufferSize: 0, + }) +} + +// dialConnection dials a named pipe connection to the specified address. +func dialConnection(addr string) (net.Conn, error) { + return winio.DialPipe(addr, nil) +} diff --git a/cmd/ttrpc-stress/main.go b/cmd/ttrpc-stress/main.go new file mode 100644 index 000000000..919d2bc37 --- /dev/null +++ b/cmd/ttrpc-stress/main.go @@ -0,0 +1,203 @@ +/* + Copyright The containerd 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 main + +import ( + "context" + "flag" + "fmt" + "log" + "os" + "strconv" + + ttrpc "github.com/containerd/ttrpc" + payload "github.com/containerd/ttrpc/cmd/ttrpc-stress/payload" + + "golang.org/x/sync/errgroup" +) + +// main is the entry point of the stress utility. +func main() { + // Define a flag for displaying usage information. + flagHelp := flag.Bool("help", false, "Display usage") + flag.Parse() + + // Check if help flag is set or if there are insufficient arguments. + if *flagHelp || flag.NArg() < 2 { + usage() + } + + // Switch based on the first argument to determine mode (server or client). + switch flag.Arg(0) { + case "server": + // Ensure correct number of arguments for server mode. + if flag.NArg() != 2 { + usage() + } + + addr := flag.Arg(1) + + // Run the server and handle any errors. + err := runServer(context.Background(), addr) + if err != nil { + log.Fatalf("error: %s", err) + } + + case "client": + // Ensure correct number of arguments for client mode. + if flag.NArg() != 4 { + usage() + } + + addr := flag.Arg(1) + + // Parse iterations and workers arguments. + iters, err := strconv.Atoi(flag.Arg(2)) + if err != nil { + log.Fatalf("failed parsing iters: %s", err) + } + + workers, err := strconv.Atoi(flag.Arg(3)) + if err != nil { + log.Fatalf("failed parsing workers: %s", err) + } + + // Run the client and handle any errors. + err = runClient(context.Background(), addr, iters, workers) + if err != nil { + log.Fatalf("runtime error: %s", err) + } + + default: + // Display usage information if the mode is unrecognized. + usage() + } +} + +// usage prints the usage information and exits the program. +// usage prints the usage information for the program and exits. +func usage() { + fmt.Fprintf(os.Stderr, `Usage: + stress server + Run the server with the specified unix socket or named pipe. + stress client + Run the client with the specified unix socket or named pipe, number of ITERATIONS, and number of WORKERS. +`) + os.Exit(1) +} + +// runServer sets up and runs the server. +func runServer(ctx context.Context, addr string) error { + log.Printf("Starting server on %s", addr) + + // Listen for connections on the specified address. + l, err := listenConnection(addr) + if err != nil { + return fmt.Errorf("failed listening on %s: %w", addr, err) + } + + // Create a new ttrpc server. + server, err := ttrpc.NewServer() + if err != nil { + return fmt.Errorf("failed creating ttrpc server: %w", err) + } + + // Register a service and method with the server. + server.Register("ttrpc.stress.test.v1", map[string]ttrpc.Method{ + "TEST": func(_ context.Context, unmarshal func(interface{}) error) (interface{}, error) { + req := &payload.Payload{} + // Unmarshal the request payload. + if err := unmarshal(req); err != nil { + log.Fatalf("failed unmarshalling request: %s", err) + } + id := req.Value + log.Printf("got request: %d", id) + // Return the same payload as the response. + return &payload.Payload{Value: id}, nil + }, + }) + + // Serve the server and handle any errors. + if err := server.Serve(ctx, l); err != nil { + return fmt.Errorf("failed serving server: %w", err) + } + return nil +} + +// runClient sets up and runs the client. +func runClient(ctx context.Context, addr string, iters int, workers int) error { + log.Printf("Starting client on %s", addr) + + // Dial a connection to the specified pipe. + c, err := dialConnection(addr) + if err != nil { + return fmt.Errorf("failed dialing connection to %s: %w", addr, err) + } + + // Create a new ttrpc client. + client := ttrpc.NewClient(c) + ch := make(chan int) + var eg errgroup.Group + + // Start worker goroutines to send requests. + for i := 0; i < workers; i++ { + eg.Go(func() error { + for { + i, ok := <-ch + if !ok { + return nil + } + // Send the request and handle any errors. + if err := send(ctx, client, uint32(i)); err != nil { + return fmt.Errorf("failed sending request: %w", err) + } + } + }) + } + + // Send iterations to the channel. + for i := 0; i < iters; i++ { + ch <- i + } + close(ch) + + // Wait for all goroutines to finish. + if err := eg.Wait(); err != nil { + return fmt.Errorf("failed waiting for goroutines: %w", err) + } + return nil +} + +// send sends a request to the server and verifies the response. +func send(ctx context.Context, client *ttrpc.Client, id uint32) error { + req := &payload.Payload{Value: id} + resp := &payload.Payload{} + + log.Printf("sending request: %d", id) + // Call the server method and handle any errors. + if err := client.Call(ctx, "ttrpc.stress.test.v1", "TEST", req, resp); err != nil { + return err + } + + ret := resp.Value + log.Printf("got response: %d", ret) + // Verify the response matches the request. + if ret != id { + return fmt.Errorf("expected return value %d but got %d", id, ret) + } + return nil +} diff --git a/cmd/ttrpc-stress/payload/doc.go b/cmd/ttrpc-stress/payload/doc.go new file mode 100644 index 000000000..182891b19 --- /dev/null +++ b/cmd/ttrpc-stress/payload/doc.go @@ -0,0 +1,17 @@ +/* + Copyright The containerd 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 payload diff --git a/cmd/ttrpc-stress/payload/payload.pb.go b/cmd/ttrpc-stress/payload/payload.pb.go new file mode 100644 index 000000000..bd1815b15 --- /dev/null +++ b/cmd/ttrpc-stress/payload/payload.pb.go @@ -0,0 +1,162 @@ +// +//Copyright The containerd 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. + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.28.1 +// protoc v3.20.1 +// source: github.com/containerd/ttrpc/cmd/ttrpc-stress/payload/payload.proto + +package payload + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type Payload struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Value uint32 `protobuf:"varint,1,opt,name=value,proto3" json:"value,omitempty"` +} + +func (x *Payload) Reset() { + *x = Payload{} + if protoimpl.UnsafeEnabled { + mi := &file_github_com_containerd_ttrpc_cmd_ttrpc_stress_payload_payload_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Payload) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Payload) ProtoMessage() {} + +func (x *Payload) ProtoReflect() protoreflect.Message { + mi := &file_github_com_containerd_ttrpc_cmd_ttrpc_stress_payload_payload_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Payload.ProtoReflect.Descriptor instead. +func (*Payload) Descriptor() ([]byte, []int) { + return file_github_com_containerd_ttrpc_cmd_ttrpc_stress_payload_payload_proto_rawDescGZIP(), []int{0} +} + +func (x *Payload) GetValue() uint32 { + if x != nil { + return x.Value + } + return 0 +} + +var File_github_com_containerd_ttrpc_cmd_ttrpc_stress_payload_payload_proto protoreflect.FileDescriptor + +var file_github_com_containerd_ttrpc_cmd_ttrpc_stress_payload_payload_proto_rawDesc = []byte{ + 0x0a, 0x42, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x6e, + 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2f, 0x74, 0x74, 0x72, 0x70, 0x63, 0x2f, 0x63, 0x6d, + 0x64, 0x2f, 0x74, 0x74, 0x72, 0x70, 0x63, 0x2d, 0x73, 0x74, 0x72, 0x65, 0x73, 0x73, 0x2f, 0x70, + 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x2f, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x22, 0x1f, 0x0a, + 0x07, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x42, 0x36, + 0x5a, 0x34, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x6e, + 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2f, 0x74, 0x74, 0x72, 0x70, 0x63, 0x2f, 0x63, 0x6d, + 0x64, 0x2f, 0x74, 0x74, 0x72, 0x70, 0x63, 0x2d, 0x73, 0x74, 0x72, 0x65, 0x73, 0x73, 0x2f, 0x70, + 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_github_com_containerd_ttrpc_cmd_ttrpc_stress_payload_payload_proto_rawDescOnce sync.Once + file_github_com_containerd_ttrpc_cmd_ttrpc_stress_payload_payload_proto_rawDescData = file_github_com_containerd_ttrpc_cmd_ttrpc_stress_payload_payload_proto_rawDesc +) + +func file_github_com_containerd_ttrpc_cmd_ttrpc_stress_payload_payload_proto_rawDescGZIP() []byte { + file_github_com_containerd_ttrpc_cmd_ttrpc_stress_payload_payload_proto_rawDescOnce.Do(func() { + file_github_com_containerd_ttrpc_cmd_ttrpc_stress_payload_payload_proto_rawDescData = protoimpl.X.CompressGZIP(file_github_com_containerd_ttrpc_cmd_ttrpc_stress_payload_payload_proto_rawDescData) + }) + return file_github_com_containerd_ttrpc_cmd_ttrpc_stress_payload_payload_proto_rawDescData +} + +var file_github_com_containerd_ttrpc_cmd_ttrpc_stress_payload_payload_proto_msgTypes = make([]protoimpl.MessageInfo, 1) +var file_github_com_containerd_ttrpc_cmd_ttrpc_stress_payload_payload_proto_goTypes = []interface{}{ + (*Payload)(nil), // 0: payload.Payload +} +var file_github_com_containerd_ttrpc_cmd_ttrpc_stress_payload_payload_proto_depIdxs = []int32{ + 0, // [0:0] is the sub-list for method output_type + 0, // [0:0] is the sub-list for method input_type + 0, // [0:0] is the sub-list for extension type_name + 0, // [0:0] is the sub-list for extension extendee + 0, // [0:0] is the sub-list for field type_name +} + +func init() { file_github_com_containerd_ttrpc_cmd_ttrpc_stress_payload_payload_proto_init() } +func file_github_com_containerd_ttrpc_cmd_ttrpc_stress_payload_payload_proto_init() { + if File_github_com_containerd_ttrpc_cmd_ttrpc_stress_payload_payload_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_github_com_containerd_ttrpc_cmd_ttrpc_stress_payload_payload_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Payload); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_github_com_containerd_ttrpc_cmd_ttrpc_stress_payload_payload_proto_rawDesc, + NumEnums: 0, + NumMessages: 1, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_github_com_containerd_ttrpc_cmd_ttrpc_stress_payload_payload_proto_goTypes, + DependencyIndexes: file_github_com_containerd_ttrpc_cmd_ttrpc_stress_payload_payload_proto_depIdxs, + MessageInfos: file_github_com_containerd_ttrpc_cmd_ttrpc_stress_payload_payload_proto_msgTypes, + }.Build() + File_github_com_containerd_ttrpc_cmd_ttrpc_stress_payload_payload_proto = out.File + file_github_com_containerd_ttrpc_cmd_ttrpc_stress_payload_payload_proto_rawDesc = nil + file_github_com_containerd_ttrpc_cmd_ttrpc_stress_payload_payload_proto_goTypes = nil + file_github_com_containerd_ttrpc_cmd_ttrpc_stress_payload_payload_proto_depIdxs = nil +} diff --git a/cmd/ttrpc-stress/payload/payload.proto b/cmd/ttrpc-stress/payload/payload.proto new file mode 100644 index 000000000..c62d5310c --- /dev/null +++ b/cmd/ttrpc-stress/payload/payload.proto @@ -0,0 +1,25 @@ +/* + Copyright The containerd 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. +*/ + +syntax = "proto3"; + +package payload; + +option go_package = "github.com/containerd/ttrpc/cmd/ttrpc-stress/payload"; + +message Payload { + uint32 value = 1; +} \ No newline at end of file diff --git a/go.mod b/go.mod index bd6b82027..1dc2e53ac 100644 --- a/go.mod +++ b/go.mod @@ -3,10 +3,12 @@ module github.com/containerd/ttrpc go 1.22 require ( + github.com/Microsoft/go-winio v0.6.2 github.com/containerd/log v0.1.0 github.com/gogo/protobuf v1.3.2 github.com/golang/protobuf v1.5.4 github.com/prometheus/procfs v0.6.0 + golang.org/x/sync v0.8.0 golang.org/x/sys v0.26.0 google.golang.org/genproto/googleapis/rpc v0.0.0-20241021214115-324edc3d5d38 google.golang.org/grpc v1.69.2 diff --git a/go.sum b/go.sum index d90c5bb67..de7c00d28 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,5 @@ +github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= +github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -39,6 +41,8 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= +golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=