diff --git a/Makefile b/Makefile index 825748a..2bb068d 100644 --- a/Makefile +++ b/Makefile @@ -19,7 +19,7 @@ test: $(OVAL) .PHONY: run run: $(OVAL) - $(OVAL) --size 4k-16k --time $(EXEC_TIME) --num_obj 1024 --num_worker 4 --bucket "test-bucket,test-bucket2" --endpoint http://localhost:9000 --save test.json + $(OVAL) --size 4k-16k --time $(EXEC_TIME) --num_obj 1024 --num_worker 4 --bucket "test-bucket,test-bucket2" --ope_ratio 8,8,8,1 --endpoint http://localhost:9000 --save test.json $(OVAL) --time 3s --load test.json .PHONY: run-multi-process @@ -30,7 +30,7 @@ run-multi-process: $(OVAL) .PHONY: run-leader run-leader: $(OVAL) - $(OVAL) leader --follower_list "http://localhost:8080,http://localhost:8081,http://localhost:8082" --size 4k-16k --time $(EXEC_TIME) --num_obj 1024 --num_worker 4 --bucket "test-bucket,test-bucket2" --endpoint http://localhost:9000 + $(OVAL) leader --follower_list "http://localhost:8080,http://localhost:8081,http://localhost:8082" --size 4k-16k --time $(EXEC_TIME) --num_obj 1024 --num_worker 4 --bucket "test-bucket,test-bucket2" --ope_ratio 8,8,8,1 --endpoint http://localhost:9000 .PHONY: run-followers run-followers: $(OVAL) diff --git a/README.md b/README.md index 3dfe8ea..d9e6bb0 100644 --- a/README.md +++ b/README.md @@ -65,38 +65,47 @@ Just build and run Oval. #### Example 1: Success case ``` -$ ./oval --size 4k-16k --time 5s --num_obj 1024 --num_worker 4 --bucket "test-bucket,test-bucket2" --endpoint http://localhost:9000 --save test.json -2022/12/31 21:31:04 worker.go:33: Worker ID = 0x1e77, Key = [ov0000000000, ov00000000ff] -2022/12/31 21:31:04 worker.go:33: Worker ID = 0x1e78, Key = [ov0000000100, ov00000001ff] -2022/12/31 21:31:04 worker.go:33: Worker ID = 0x1e79, Key = [ov0000000200, ov00000002ff] -2022/12/31 21:31:04 worker.go:33: Worker ID = 0x1e7a, Key = [ov0000000300, ov00000003ff] -2022/12/31 21:31:04 runner.go:151: Validation start. -2022/12/31 21:31:09 runner.go:191: Validation finished. -2022/12/31 21:31:09 stat.go:32: Statistics report. -2022/12/31 21:31:09 stat.go:33: put count: 670 -2022/12/31 21:31:09 stat.go:34: get count: 609 -2022/12/31 21:31:09 stat.go:35: get (for validation) count: 1257 -2022/12/31 21:31:09 stat.go:36: delete count: 575 +$ ./oval --size 4k-16k --time 5s --num_obj 1024 --num_worker 4 --bucket "test-bucket,test-bucket2" --endpoint http://localhost:9000 +2023/02/12 14:32:01 runner.go:108: Clearing bucket 'test-bucket'. +2023/02/12 14:32:02 runner.go:113: Bucket cleared successfully. +2023/02/12 14:32:02 runner.go:108: Clearing bucket 'test-bucket2'. +2023/02/12 14:32:03 runner.go:113: Bucket cleared successfully. +2023/02/12 14:32:03 worker.go:33: Worker ID = 0x3595, Key = [ov0000000000, ov00000000ff] +2023/02/12 14:32:03 worker.go:33: Worker ID = 0x3596, Key = [ov0001000000, ov00010000ff] +2023/02/12 14:32:03 worker.go:33: Worker ID = 0x3597, Key = [ov0002000000, ov00020000ff] +2023/02/12 14:32:03 worker.go:33: Worker ID = 0x3598, Key = [ov0003000000, ov00030000ff] +2023/02/12 14:32:03 runner.go:153: Validation start. +2023/02/12 14:32:08 runner.go:197: Validation finished. +2023/02/12 14:32:08 stat.go:37: Statistics report. +2023/02/12 14:32:08 stat.go:38: put count: 618 +2023/02/12 14:32:08 stat.go:39: get count: 483 +2023/02/12 14:32:08 stat.go:40: get (for validation) count: 1140 +2023/02/12 14:32:08 stat.go:41: list count: 0 +2023/02/12 14:32:08 stat.go:42: delete count: 50 ``` #### Example 2: Data corruption case ``` -$ ./oval --size 4k-16k --time 5s --num_obj 1024 --num_worker 4 --bucket "test-bucket,test-bucket2" --endpoint http://localhost:9000 --save test.json -2023/01/01 14:54:41 worker.go:33: Worker ID = 0x2009, Key = [ov0000000000, ov00000000ff] -2023/01/01 14:54:41 worker.go:33: Worker ID = 0x200a, Key = [ov0000000100, ov00000001ff] -2023/01/01 14:54:41 worker.go:33: Worker ID = 0x200b, Key = [ov0000000200, ov00000002ff] -2023/01/01 14:54:41 worker.go:33: Worker ID = 0x200c, Key = [ov0000000300, ov00000003ff] -2023/01/01 14:54:41 runner.go:151: Validation start. -2023/01/01 14:54:41 worker.go:101: Data validation error occurred after put. +$ ./oval --size 4k-16k --time 5s --num_obj 1024 --num_worker 4 --bucket "test-bucket,test-bucket2" --endpoint http://localhost:9000 +2023/02/12 14:43:46 runner.go:108: Clearing bucket 'test-bucket'. +2023/02/12 14:43:47 runner.go:113: Bucket cleared successfully. +2023/02/12 14:43:47 runner.go:108: Clearing bucket 'test-bucket2'. +2023/02/12 14:43:47 runner.go:113: Bucket cleared successfully. +2023/02/12 14:43:47 worker.go:33: Worker ID = 0x8e14, Key = [ov0000000000, ov00000000ff] +2023/02/12 14:43:47 worker.go:33: Worker ID = 0x8e15, Key = [ov0001000000, ov00010000ff] +2023/02/12 14:43:47 worker.go:33: Worker ID = 0x8e16, Key = [ov0002000000, ov00020000ff] +2023/02/12 14:43:47 worker.go:33: Worker ID = 0x8e17, Key = [ov0003000000, ov00030000ff] +2023/02/12 14:43:47 runner.go:153: Validation start. +2023/02/12 14:43:47 worker.go:101: Data validation error occurred after put. - WriteCount is wrong. (expected = "2", actual = "1") - OffsetInObject is wrong. (expected = "0", actual = "256") 00000000 74 65 73 74 2d 62 75 63 6b 65 74 20 20 20 20 20 |test-bucket | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ bucket name -00000010 6f 76 30 30 30 30 30 30 30 31 66 34 01 00 00 00 |ov00000001f4....| +00000010 6f 76 30 30 30 32 30 30 30 30 32 35 01 00 00 00 |ov0002000025....| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ key name ^^^^^^^^^^^ write count -00000020 00 01 00 00 0a 20 00 00 18 a1 8d 78 2d f1 05 00 |..... .....x-...| +00000020 00 01 00 00 16 8e 00 00 67 ea e0 36 7a f4 05 00 |........g..6z...| ^^^^^^^^^^^ byte offset in this object ^^^^^^^^^^^ worker ID ^^^^^^^^^^^^^^^^^^^^^^^ unix time (micro sec) @@ -114,13 +123,14 @@ $ ./oval --size 4k-16k --time 5s --num_obj 1024 --num_worker 4 --bucket "test-bu 000000e0 e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 ea eb ec ed ee ef |................| 000000f0 f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe ff |................| -2023/01/01 14:54:41 runner.go:193: Validation finished. -2023/01/01 14:54:41 stat.go:32: Statistics report. -2023/01/01 14:54:41 stat.go:33: put count: 93 -2023/01/01 14:54:41 stat.go:34: get count: 66 -2023/01/01 14:54:41 stat.go:35: get (for validation) count: 157 -2023/01/01 14:54:41 stat.go:36: delete count: 64 -2023/01/01 14:54:41 root.go:52: r.Run() failed. +2023/02/12 14:43:47 runner.go:197: Validation finished. +2023/02/12 14:43:47 stat.go:37: Statistics report. +2023/02/12 14:43:47 stat.go:38: put count: 23 +2023/02/12 14:43:47 stat.go:39: get count: 11 +2023/02/12 14:43:47 stat.go:40: get (for validation) count: 30 +2023/02/12 14:43:47 stat.go:41: list count: 0 +2023/02/12 14:43:47 stat.go:42: delete count: 7 +2023/02/12 14:43:47 root.go:66: r.Run() failed. ``` ### The multi-process mode @@ -135,56 +145,66 @@ $ ./oval --size 4k-16k --time 5s --num_obj 1024 --num_worker 4 --bucket "test-bu ``` $ ./oval follower --follower_port 8080 -2022/12/31 21:31:47 follower.go:41: Start server. port = 8080 -2022/12/31 21:32:04 follower.go:46: Received a init request. -2022/12/31 21:32:04 follower.go:62: Received a start request. -2022/12/31 21:32:04 follower.go:119: ID: 0 -2022/12/31 21:32:04 follower.go:120: Context: {http://localhost:9000 [test-bucket test-bucket2] 1024 4 4096 16384 0 []} -2022/12/31 21:32:04 follower.go:121: OpeRatio: [0.3333333333333333 0.3333333333333333 0.3333333333333333] -2022/12/31 21:32:04 follower.go:122: TimeInMs: 5000 -2022/12/31 21:32:05 worker.go:33: Worker ID = 0xd681, Key = [ov0000000000, ov00000000ff] -2022/12/31 21:32:05 worker.go:33: Worker ID = 0xd682, Key = [ov0000000100, ov00000001ff] -2022/12/31 21:32:05 worker.go:33: Worker ID = 0xd683, Key = [ov0000000200, ov00000002ff] -2022/12/31 21:32:05 worker.go:33: Worker ID = 0xd684, Key = [ov0000000300, ov00000003ff] -2022/12/31 21:32:05 runner.go:151: Validation start. -2022/12/31 21:32:10 runner.go:191: Validation finished. -2022/12/31 21:32:10 stat.go:32: Statistics report. -2022/12/31 21:32:10 stat.go:33: put count: 479 -2022/12/31 21:32:10 stat.go:34: get count: 393 -2022/12/31 21:32:10 stat.go:35: get (for validation) count: 892 -2022/12/31 21:32:10 stat.go:36: delete count: 399 +2023/02/12 14:41:40 follower.go:41: Start server. port = 8080 +2023/02/12 14:41:53 follower.go:46: Received a init request. +2023/02/12 14:41:53 follower.go:62: Received a start request. +2023/02/12 14:41:53 follower.go:119: ID: 0 +2023/02/12 14:41:53 follower.go:120: Context: {http://localhost:9000 [test-bucket test-bucket2] 1024 4 4096 16384 0 []} +2023/02/12 14:41:53 follower.go:121: OpeRatio: [0.3333333333333333 0.3333333333333333 0.3333333333333333 0] +2023/02/12 14:41:53 follower.go:122: TimeInMs: 5000 +2023/02/12 14:41:53 runner.go:108: Clearing bucket 'test-bucket'. +2023/02/12 14:41:53 runner.go:113: Bucket cleared successfully. +2023/02/12 14:41:53 runner.go:108: Clearing bucket 'test-bucket2'. +2023/02/12 14:41:53 runner.go:113: Bucket cleared successfully. +2023/02/12 14:41:53 worker.go:33: Worker ID = 0x7ea7, Key = [ov0000000000, ov00000000ff] +2023/02/12 14:41:53 worker.go:33: Worker ID = 0x7ea8, Key = [ov0001000000, ov00010000ff] +2023/02/12 14:41:53 worker.go:33: Worker ID = 0x7ea9, Key = [ov0002000000, ov00020000ff] +2023/02/12 14:41:53 worker.go:33: Worker ID = 0x7eaa, Key = [ov0003000000, ov00030000ff] +2023/02/12 14:41:53 runner.go:153: Validation start. +2023/02/12 14:41:58 runner.go:197: Validation finished. +2023/02/12 14:41:58 stat.go:37: Statistics report. +2023/02/12 14:41:58 stat.go:38: put count: 479 +2023/02/12 14:41:58 stat.go:39: get count: 402 +2023/02/12 14:41:58 stat.go:40: get (for validation) count: 872 +2023/02/12 14:41:58 stat.go:41: list count: 0 +2023/02/12 14:41:58 stat.go:42: delete count: 383 ``` ##### follower2 ``` $ ./oval follower --follower_port 8081 -2022/12/31 21:31:53 follower.go:41: Start server. port = 8081 -2022/12/31 21:32:04 follower.go:46: Received a init request. -2022/12/31 21:32:04 follower.go:62: Received a start request. -2022/12/31 21:32:04 follower.go:119: ID: 1 -2022/12/31 21:32:04 follower.go:120: Context: {http://localhost:9000 [test-bucket test-bucket2] 1024 4 4096 16384 0 []} -2022/12/31 21:32:04 follower.go:121: OpeRatio: [0.3333333333333333 0.3333333333333333 0.3333333333333333] -2022/12/31 21:32:04 follower.go:122: TimeInMs: 5000 -2022/12/31 21:32:05 worker.go:33: Worker ID = 0x6518, Key = [ov0100000000, ov01000000ff] -2022/12/31 21:32:05 worker.go:33: Worker ID = 0x6519, Key = [ov0100000100, ov01000001ff] -2022/12/31 21:32:05 worker.go:33: Worker ID = 0x651a, Key = [ov0100000200, ov01000002ff] -2022/12/31 21:32:05 worker.go:33: Worker ID = 0x651b, Key = [ov0100000300, ov01000003ff] -2022/12/31 21:32:05 runner.go:151: Validation start. -2022/12/31 21:32:10 runner.go:191: Validation finished. -2022/12/31 21:32:10 stat.go:32: Statistics report. -2022/12/31 21:32:10 stat.go:33: put count: 466 -2022/12/31 21:32:10 stat.go:34: get count: 430 -2022/12/31 21:32:10 stat.go:35: get (for validation) count: 886 -2022/12/31 21:32:10 stat.go:36: delete count: 416 +2023/02/12 14:41:45 follower.go:41: Start server. port = 8081 +2023/02/12 14:41:53 follower.go:46: Received a init request. +2023/02/12 14:41:53 follower.go:62: Received a start request. +2023/02/12 14:41:53 follower.go:119: ID: 1 +2023/02/12 14:41:53 follower.go:120: Context: {http://localhost:9000 [test-bucket test-bucket2] 1024 4 4096 16384 0 []} +2023/02/12 14:41:53 follower.go:121: OpeRatio: [0.3333333333333333 0.3333333333333333 0.3333333333333333 0] +2023/02/12 14:41:53 follower.go:122: TimeInMs: 5000 +2023/02/12 14:41:53 runner.go:108: Clearing bucket 'test-bucket'. +2023/02/12 14:41:53 runner.go:113: Bucket cleared successfully. +2023/02/12 14:41:53 runner.go:108: Clearing bucket 'test-bucket2'. +2023/02/12 14:41:53 runner.go:113: Bucket cleared successfully. +2023/02/12 14:41:53 worker.go:33: Worker ID = 0x5803, Key = [ov0100000000, ov01000000ff] +2023/02/12 14:41:53 worker.go:33: Worker ID = 0x5804, Key = [ov0101000000, ov01010000ff] +2023/02/12 14:41:53 worker.go:33: Worker ID = 0x5805, Key = [ov0102000000, ov01020000ff] +2023/02/12 14:41:53 worker.go:33: Worker ID = 0x5806, Key = [ov0103000000, ov01030000ff] +2023/02/12 14:41:53 runner.go:153: Validation start. +2023/02/12 14:41:58 runner.go:197: Validation finished. +2023/02/12 14:41:58 stat.go:37: Statistics report. +2023/02/12 14:41:58 stat.go:38: put count: 488 +2023/02/12 14:41:58 stat.go:39: get count: 430 +2023/02/12 14:41:58 stat.go:40: get (for validation) count: 892 +2023/02/12 14:41:58 stat.go:41: list count: 0 +2023/02/12 14:41:58 stat.go:42: delete count: 392 ``` ##### leader ``` $ ./oval leader --follower_list "http://localhost:8080,http://localhost:8081" --size 4k-16k --time 5s --num_obj 1024 --num_worker 4 --bucket "test-bucket,test-bucket2" --endpoint http://localhost:9000 -2022/12/31 21:32:04 leader.go:34: Sent start requests to all followers. -2022/12/31 21:32:10 leader.go:40: The report from followers: +2023/02/12 14:41:53 leader.go:31: Sent start requests to all followers. +2023/02/12 14:41:58 leader.go:37: The report from followers: follower: http://localhost:8080 OK follower: http://localhost:8081 diff --git a/cmd/root.go b/cmd/root.go index cc8db17..c7dedc2 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -12,7 +12,7 @@ import ( ) var ( - numObj int64 + numObj int numWorker int sizePattern string execTime time.Duration @@ -114,9 +114,21 @@ func handleCommonFlags() { log.Fatal(err) } - if numObj%int64(numWorker) != 0 { + if numWorker >= 256 { + log.Fatal("The number of workers must be less than 256.") + } + + if numObj > 0x1000000 { + log.Fatal("The number of objects must be less than 16777216.") + } + + if numObj < numWorker { + log.Fatal("The number of objects must be larger than or equal to the number of workers.") + } + + if numObj%numWorker != 0 { log.Printf("warning: The number of objects (%d) is not divisible by the number of workers (%d). Only %d objects will be used.\n", - numObj, numWorker, numObj/int64(numWorker*numWorker)) + numObj, numWorker, numObj/numWorker*numWorker) } execContext = &runner.ExecutionContext{ @@ -130,11 +142,11 @@ func handleCommonFlags() { } func defineCommonFlags(cmd *cobra.Command) { - cmd.Flags().Int64Var(&numObj, "num_obj", 10, "The maximum number of objects.") + cmd.Flags().IntVar(&numObj, "num_obj", 10, "The maximum number of objects per process.") cmd.Flags().IntVar(&numWorker, "num_worker", 1, "The number of workers per process.") cmd.Flags().StringVar(&sizePattern, "size", "4k", "The size of object. Should be in the form like \"8k\" or \"4k-2m\". The unit \"g\" or \"G\" is not allowed.") cmd.Flags().DurationVar(&execTime, "time", time.Second*3, "Time duration for run the workload.") cmd.Flags().StringSliceVar(&bucketNames, "bucket", nil, "The name list of the buckets. e.g. \"bucket1,bucket2\"") - cmd.Flags().StringVar(&opeRatioStr, "ope_ratio", "1,1,1", "The ration of put, get and delete operations. e.g. \"2,3,1\"") + cmd.Flags().StringVar(&opeRatioStr, "ope_ratio", "1,1,1,0", "The ration of put, get, delete and list operations. e.g. \"2,3,1,1\"") cmd.Flags().StringVar(&endpoint, "endpoint", "", "The endpoint URL and TCP port number. e.g. \"http://127.0.0.1:9000\"") } diff --git a/go.mod b/go.mod index d0f8021..e4a7006 100644 --- a/go.mod +++ b/go.mod @@ -3,9 +3,9 @@ module github.com/peng225/oval go 1.19 require ( - github.com/aws/aws-sdk-go-v2 v1.17.3 - github.com/aws/aws-sdk-go-v2/config v1.18.8 - github.com/aws/aws-sdk-go-v2/service/s3 v1.30.0 + github.com/aws/aws-sdk-go-v2 v1.17.4 + github.com/aws/aws-sdk-go-v2/config v1.18.12 + github.com/aws/aws-sdk-go-v2/service/s3 v1.30.2 github.com/dsnet/golib/memfile v1.0.0 github.com/pkg/profile v1.7.0 github.com/spf13/cobra v1.6.1 @@ -14,19 +14,19 @@ require ( require ( github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.10 // indirect - github.com/aws/aws-sdk-go-v2/credentials v1.13.8 // indirect - github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.21 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.27 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.21 // indirect - github.com/aws/aws-sdk-go-v2/internal/ini v1.3.28 // indirect - github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.18 // indirect + github.com/aws/aws-sdk-go-v2/credentials v1.13.12 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.22 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.28 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.22 // indirect + github.com/aws/aws-sdk-go-v2/internal/ini v1.3.29 // indirect + github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.19 // indirect github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.11 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.22 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.21 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.21 // indirect - github.com/aws/aws-sdk-go-v2/service/sso v1.12.0 // indirect - github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.0 // indirect - github.com/aws/aws-sdk-go-v2/service/sts v1.18.0 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.23 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.22 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.22 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.12.1 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.1 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.18.3 // indirect github.com/aws/smithy-go v1.13.5 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/felixge/fgprof v0.9.3 // indirect diff --git a/go.sum b/go.sum index 073e1f9..dc9599d 100644 --- a/go.sum +++ b/go.sum @@ -1,37 +1,37 @@ -github.com/aws/aws-sdk-go-v2 v1.17.3 h1:shN7NlnVzvDUgPQ+1rLMSxY8OWRNDRYtiqe0p/PgrhY= -github.com/aws/aws-sdk-go-v2 v1.17.3/go.mod h1:uzbQtefpm44goOPmdKyAlXSNcwlRgF3ePWVW6EtJvvw= +github.com/aws/aws-sdk-go-v2 v1.17.4 h1:wyC6p9Yfq6V2y98wfDsj6OnNQa4w2BLGCLIxzNhwOGY= +github.com/aws/aws-sdk-go-v2 v1.17.4/go.mod h1:uzbQtefpm44goOPmdKyAlXSNcwlRgF3ePWVW6EtJvvw= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.10 h1:dK82zF6kkPeCo8J1e+tGx4JdvDIQzj7ygIoLg8WMuGs= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.10/go.mod h1:VeTZetY5KRJLuD/7fkQXMU6Mw7H5m/KP2J5Iy9osMno= -github.com/aws/aws-sdk-go-v2/config v1.18.8 h1:lDpy0WM8AHsywOnVrOHaSMfpaiV2igOw8D7svkFkXVA= -github.com/aws/aws-sdk-go-v2/config v1.18.8/go.mod h1:5XCmmyutmzzgkpk/6NYTjeWb6lgo9N170m1j6pQkIBs= -github.com/aws/aws-sdk-go-v2/credentials v1.13.8 h1:vTrwTvv5qAwjWIGhZDSBH/oQHuIQjGmD232k01FUh6A= -github.com/aws/aws-sdk-go-v2/credentials v1.13.8/go.mod h1:lVa4OHbvgjVot4gmh1uouF1ubgexSCN92P6CJQpT0t8= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.21 h1:j9wi1kQ8b+e0FBVHxCqCGo4kxDU175hoDHcWAi0sauU= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.21/go.mod h1:ugwW57Z5Z48bpvUyZuaPy4Kv+vEfJWnIrky7RmkBvJg= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.27 h1:I3cakv2Uy1vNmmhRQmFptYDxOvBnwCdNwyw63N0RaRU= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.27/go.mod h1:a1/UpzeyBBerajpnP5nGZa9mGzsBn5cOKxm6NWQsvoI= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.21 h1:5NbbMrIzmUn/TXFqAle6mgrH5m9cOvMLRGL7pnG8tRE= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.21/go.mod h1:+Gxn8jYn5k9ebfHEqlhrMirFjSW0v0C9fI+KN5vk2kE= -github.com/aws/aws-sdk-go-v2/internal/ini v1.3.28 h1:KeTxcGdNnQudb46oOl4d90f2I33DF/c6q3RnZAmvQdQ= -github.com/aws/aws-sdk-go-v2/internal/ini v1.3.28/go.mod h1:yRZVr/iT0AqyHeep00SZ4YfBAKojXz08w3XMBscdi0c= -github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.18 h1:H/mF2LNWwX00lD6FlYfKpLLZgUW7oIzCBkig78x4Xok= -github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.18/go.mod h1:T2Ku+STrYQ1zIkL1wMvj8P3wWQaaCMKNdz70MT2FLfE= +github.com/aws/aws-sdk-go-v2/config v1.18.12 h1:fKs/I4wccmfrNRO9rdrbMO1NgLxct6H9rNMiPdBxHWw= +github.com/aws/aws-sdk-go-v2/config v1.18.12/go.mod h1:J36fOhj1LQBr+O4hJCiT8FwVvieeoSGOtPuvhKlsNu8= +github.com/aws/aws-sdk-go-v2/credentials v1.13.12 h1:Cb+HhuEnV19zHRaYYVglwvdHGMJWbdsyP4oHhw04xws= +github.com/aws/aws-sdk-go-v2/credentials v1.13.12/go.mod h1:37HG2MBroXK3jXfxVGtbM2J48ra2+Ltu+tmwr/jO0KA= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.22 h1:3aMfcTmoXtTZnaT86QlVaYh+BRMbvrrmZwIQ5jWqCZQ= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.22/go.mod h1:YGSIJyQ6D6FjKMQh16hVFSIUD54L4F7zTGePqYMYYJU= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.28 h1:r+XwaCLpIvCKjBIYy/HVZujQS9tsz5ohHG3ZIe0wKoE= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.28/go.mod h1:3lwChorpIM/BhImY/hy+Z6jekmN92cXGPI1QJasVPYY= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.22 h1:7AwGYXDdqRQYsluvKFmWoqpcOQJ4bH634SkYf3FNj/A= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.22/go.mod h1:EqK7gVrIGAHyZItrD1D8B0ilgwMD1GiWAmbU4u/JHNk= +github.com/aws/aws-sdk-go-v2/internal/ini v1.3.29 h1:J4xhFd6zHhdF9jPP0FQJ6WknzBboGMBNjKOv4iTuw4A= +github.com/aws/aws-sdk-go-v2/internal/ini v1.3.29/go.mod h1:TwuqRBGzxjQJIwH16/fOZodwXt2Zxa9/cwJC5ke4j7s= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.19 h1:FGvpyTg2LKEmMrLlpjOgkoNp9XF5CGeyAyo33LdqZW8= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.19/go.mod h1:8W88sW3PjamQpKFUQvHWWKay6ARsNvZnzU7+a4apubw= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.11 h1:y2+VQzC6Zh2ojtV2LoC0MNwHWc6qXv/j2vrQtlftkdA= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.11/go.mod h1:iV4q2hsqtNECrfmlXyord9u4zyuFEJX9eLgLpSPzWA8= -github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.22 h1:kv5vRAl00tozRxSnI0IszPWGXsJOyA7hmEUHFYqsyvw= -github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.22/go.mod h1:Od+GU5+Yx41gryN/ZGZzAJMZ9R1yn6lgA0fD5Lo5SkQ= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.21 h1:5C6XgTViSb0bunmU57b3CT+MhxULqHH2721FVA+/kDM= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.21/go.mod h1:lRToEJsn+DRA9lW4O9L9+/3hjTkUzlzyzHqn8MTds5k= -github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.21 h1:vY5siRXvW5TrOKm2qKEf9tliBfdLxdfy0i02LOcmqUo= -github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.21/go.mod h1:WZvNXT1XuH8dnJM0HvOlvk+RNn7NbAPvA/ACO0QarSc= -github.com/aws/aws-sdk-go-v2/service/s3 v1.30.0 h1:wddsyuESfviaiXk3w9N6/4iRwTg/a3gktjODY6jYQBo= -github.com/aws/aws-sdk-go-v2/service/s3 v1.30.0/go.mod h1:L2l2/q76teehcW7YEsgsDjqdsDTERJeX3nOMIFlgGUE= -github.com/aws/aws-sdk-go-v2/service/sso v1.12.0 h1:/2gzjhQowRLarkkBOGPXSRnb8sQ2RVsjdG1C/UliK/c= -github.com/aws/aws-sdk-go-v2/service/sso v1.12.0/go.mod h1:wo/B7uUm/7zw/dWhBJ4FXuw1sySU5lyIhVg1Bu2yL9A= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.0 h1:Jfly6mRxk2ZOSlbCvZfKNS7TukSx1mIzhSsqZ/IGSZI= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.0/go.mod h1:TZSH7xLO7+phDtViY/KUp9WGCJMQkLJ/VpgkTFd5gh8= -github.com/aws/aws-sdk-go-v2/service/sts v1.18.0 h1:kOO++CYo50RcTFISESluhWEi5Prhg+gaSs4whWabiZU= -github.com/aws/aws-sdk-go-v2/service/sts v1.18.0/go.mod h1:+lGbb3+1ugwKrNTWcf2RT05Xmp543B06zDFTwiTLp7I= +github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.23 h1:c5+bNdV8E4fIPteWx4HZSkqI07oY9exbfQ7JH7Yx4PI= +github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.23/go.mod h1:1jcUfF+FAOEwtIcNiHPaV4TSoZqkUIPzrohmD7fb95c= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.22 h1:LjFQf8hFuMO22HkV5VWGLBvmCLBCLPivUAmpdpnp4Vs= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.22/go.mod h1:xt0Au8yPIwYXf/GYPy/vl4K3CgwhfQMYbrH7DlUUIws= +github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.22 h1:ISLJ2BKXe4zzyZ7mp5ewKECiw0U7KpLgS3S6OxY9Cm0= +github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.22/go.mod h1:QFVbqK54XArazLvn2wvWMRBi/jGrWii46qbr5DyPGjc= +github.com/aws/aws-sdk-go-v2/service/s3 v1.30.2 h1:5EQWIFO+Hc8E2hFcXQJ1vm6ufl/PMt/6RVRDZRju2vM= +github.com/aws/aws-sdk-go-v2/service/s3 v1.30.2/go.mod h1:SXDHd6fI2RhqB7vmAzyYQCTQnpZrIprVJvYxpzW3JAM= +github.com/aws/aws-sdk-go-v2/service/sso v1.12.1 h1:lQKN/LNa3qqu2cDOQZybP7oL4nMGGiFqob0jZJaR8/4= +github.com/aws/aws-sdk-go-v2/service/sso v1.12.1/go.mod h1:IgV8l3sj22nQDd5qcAGY0WenwCzCphqdbFOpfktZPrI= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.1 h1:0bLhH6DRAqox+g0LatcjGKjjhU6Eudyys6HB6DJVPj8= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.1/go.mod h1:O1YSOg3aekZibh2SngvCRRG+cRHKKlYgxf/JBF/Kr/k= +github.com/aws/aws-sdk-go-v2/service/sts v1.18.3 h1:s49mSnsBZEXjfGBkRfmK+nPqzT7Lt3+t2SmAKNyHblw= +github.com/aws/aws-sdk-go-v2/service/sts v1.18.3/go.mod h1:b+psTJn33Q4qGoDaM7ZiOVVG8uVjGI6HaZ8WBHdgDgU= github.com/aws/smithy-go v1.13.5 h1:hgz0X/DX0dGqTYpGALqXJoRKRj5oQ7150i5FdTePzO8= github.com/aws/smithy-go v1.13.5/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= diff --git a/object/object.go b/object/object.go index bd0f1dc..7bb5142 100644 --- a/object/object.go +++ b/object/object.go @@ -11,7 +11,9 @@ import ( const ( MaxBucketNameLength = 16 MaxKeyLength = 12 - KeyPrefix = "ov" + KeyShortPrefix = "ov" + // len(KeyShortPrefix) + 2 (for process ID) + 2 (for worker ID) + KeyPrefixLength = 6 ) type Object struct { @@ -24,6 +26,7 @@ type ObjectMeta struct { ObjectList []Object `json:"objectList"` ExistingObjectIDs []int64 `json:"existingObjectIDs"` KeyIDOffset int64 `json:"keyIDOffset"` + KeyPrefix string } func (obj *Object) Clear() { @@ -40,17 +43,18 @@ func NewObject(objID int64) *Object { } func generateKey(objID int64) string { - return fmt.Sprintf("%s%010x", KeyPrefix, objID) + return fmt.Sprintf("%s%010x", KeyShortPrefix, objID) } -func NewObjectMeta(numObj, keyIDOffset int64) *ObjectMeta { +func NewObjectMeta(numObj int, keyIDOffset int64) *ObjectMeta { om := &ObjectMeta{} om.ObjectList = make([]Object, numObj) - for objID := int64(0); objID < numObj; objID++ { - om.ObjectList[objID] = *NewObject(keyIDOffset + objID) + for objID := 0; objID < numObj; objID++ { + om.ObjectList[objID] = *NewObject(keyIDOffset + int64(objID)) } om.ExistingObjectIDs = make([]int64, 0, int(math.Sqrt(float64(numObj)))) om.KeyIDOffset = keyIDOffset + om.KeyPrefix = generateKey(keyIDOffset)[:KeyPrefixLength] return om } @@ -62,7 +66,7 @@ func (om *ObjectMeta) GetRandomObject() *Object { // Caution: this function should be called while the object lock is acquired. func (om *ObjectMeta) RegisterToExistingList(key string) { - objID, err := strconv.ParseInt(key[len(KeyPrefix):], 16, 64) + objID, err := strconv.ParseInt(key[len(KeyShortPrefix):], 16, 64) if err != nil { log.Fatal(err) } diff --git a/runner/runner.go b/runner/runner.go index ecbe6e4..82c9458 100644 --- a/runner/runner.go +++ b/runner/runner.go @@ -24,7 +24,7 @@ const ( type ExecutionContext struct { Endpoint string `json:"endpoint"` BucketNames []string `json:"bucketNames"` - NumObj int64 `json:"numObj"` + NumObj int `json:"numObj"` NumWorker int `json:"numWorker"` MinSize int `json:"minSize"` MaxSize int `json:"maxSize"` @@ -105,10 +105,12 @@ func (r *Runner) init() { } } else { if r.loadFileName == "" { - err = r.client.ClearBucket(bucketName, fmt.Sprintf("%s%02x", object.KeyPrefix, r.processID)) + log.Printf("Clearing bucket '%s'.\n", bucketName) + err = r.client.ClearBucket(bucketName, fmt.Sprintf("%s%02x", object.KeyShortPrefix, r.processID)) if err != nil { log.Fatal(err) } + log.Println("Bucket cleared successfully.") } } } @@ -127,8 +129,8 @@ func (r *Runner) init() { r.execContext.Workers[i].BucketsWithObject[j] = &BucketWithObject{ BucketName: bucketName, ObjectMata: object.NewObjectMeta( - r.execContext.NumObj/int64(r.execContext.NumWorker), - r.execContext.NumObj/int64(r.execContext.NumWorker)*int64(i)+(int64(r.processID)<<32)), + r.execContext.NumObj/r.execContext.NumWorker, + (int64(r.processID)<<32)+(int64(i)<<24)), } } r.execContext.Workers[i].client = r.client @@ -180,6 +182,8 @@ func (r *Runner) Run(cancel chan struct{}) error { err = r.execContext.Workers[workerID].Get() case Delete: err = r.execContext.Workers[workerID].Delete() + case List: + err = r.execContext.Workers[workerID].List() } if err != nil { errCh <- err @@ -209,6 +213,7 @@ const ( Put Operation = iota Get Delete + List NumOperation ) @@ -219,8 +224,10 @@ func (r *Runner) selectOperation() Operation { return Put } else if randVal < r.opeRatio[0]+r.opeRatio[1] { return Get - } else { + } else if randVal < r.opeRatio[0]+r.opeRatio[1]+r.opeRatio[2] { return Delete + } else { + return List } } diff --git a/runner/worker.go b/runner/worker.go index 7c91576..b55a6fa 100644 --- a/runner/worker.go +++ b/runner/worker.go @@ -26,19 +26,19 @@ type BucketWithObject struct { ObjectMata *object.ObjectMeta `json:"objectMeta"` } -func (v *Worker) ShowInfo() { +func (w *Worker) ShowInfo() { // Only show the key range of the first bucket // because key range is the same for all buckets. - head, tail := v.BucketsWithObject[0].ObjectMata.GetHeadAndTailKey() - log.Printf("Worker ID = %#x, Key = [%s, %s]\n", v.id, head, tail) + head, tail := w.BucketsWithObject[0].ObjectMata.GetHeadAndTailKey() + log.Printf("Worker ID = %#x, Key = [%s, %s]\n", w.id, head, tail) } -func (v *Worker) Put() error { - bucketWithObj := v.selectBucketWithObject() +func (w *Worker) Put() error { + bucketWithObj := w.selectBucketWithObject() obj := bucketWithObj.ObjectMata.GetRandomObject() // Validation before write - getBeforeBody, err := v.client.GetObject(bucketWithObj.BucketName, obj.Key) + getBeforeBody, err := w.client.GetObject(bucketWithObj.BucketName, obj.Key) if err != nil { var nsk *s3_client.NoSuchKey if errors.As(err, &nsk) { @@ -60,32 +60,32 @@ func (v *Worker) Put() error { log.Println(err.Error()) return err } - err := pattern.Valid(v.id, bucketWithObj.BucketName, obj, getBeforeBody) + err := pattern.Valid(w.id, bucketWithObj.BucketName, obj, getBeforeBody) if err != nil { err = fmt.Errorf("Data validation error occurred before put.\n%w", err) log.Println(err.Error()) return err } - v.st.AddGetForValidCount() + w.st.AddGetForValidCount() } bucketWithObj.ObjectMata.RegisterToExistingList(obj.Key) obj.WriteCount++ - body, size, err := pattern.Generate(v.minSize, v.maxSize, v.id, bucketWithObj.BucketName, obj) + body, size, err := pattern.Generate(w.minSize, w.maxSize, w.id, bucketWithObj.BucketName, obj) obj.Size = size if err != nil { log.Println(err.Error()) return err } - err = v.client.PutObject(bucketWithObj.BucketName, obj.Key, body) + err = w.client.PutObject(bucketWithObj.BucketName, obj.Key, body) if err != nil { log.Println(err.Error()) return err } - v.st.AddPutCount() + w.st.AddPutCount() // Validation after write - getAfterBody, err := v.client.GetObject(bucketWithObj.BucketName, obj.Key) + getAfterBody, err := w.client.GetObject(bucketWithObj.BucketName, obj.Key) if err != nil { var nsk *s3_client.NoSuchKey if errors.As(err, &nsk) { @@ -95,25 +95,25 @@ func (v *Worker) Put() error { return err } defer getAfterBody.Close() - err = pattern.Valid(v.id, bucketWithObj.BucketName, obj, getAfterBody) + err = pattern.Valid(w.id, bucketWithObj.BucketName, obj, getAfterBody) if err != nil { err = fmt.Errorf("Data validation error occurred after put.\n%w", err) log.Println(err.Error()) return err } - v.st.AddGetForValidCount() + w.st.AddGetForValidCount() return nil } -func (v *Worker) Get() error { - bucketWithObj := v.selectBucketWithObject() +func (w *Worker) Get() error { + bucketWithObj := w.selectBucketWithObject() obj := bucketWithObj.ObjectMata.GetExistingRandomObject() if obj == nil { return nil } // Validation on get - body, err := v.client.GetObject(bucketWithObj.BucketName, obj.Key) + body, err := w.client.GetObject(bucketWithObj.BucketName, obj.Key) if err != nil { var nsk *s3_client.NoSuchKey if errors.As(err, &nsk) { @@ -123,25 +123,54 @@ func (v *Worker) Get() error { return err } defer body.Close() - err = pattern.Valid(v.id, bucketWithObj.BucketName, obj, body) + err = pattern.Valid(w.id, bucketWithObj.BucketName, obj, body) if err != nil { err = fmt.Errorf("Data validation error occurred at get operation.\n%w", err) log.Println(err.Error()) return err } - v.st.AddGetCount() + w.st.AddGetCount() return nil } -func (v *Worker) Delete() error { - bucketWithObj := v.selectBucketWithObject() +func (w *Worker) List() error { + bucketWithObj := w.selectBucketWithObject() + + objectNames, err := w.client.ListObjects(bucketWithObj.BucketName, bucketWithObj.ObjectMata.KeyPrefix) + if err != nil { + log.Println(err.Error()) + return err + } + + if len(bucketWithObj.ObjectMata.ExistingObjectIDs) != len(objectNames) { + err = fmt.Errorf("Invalid number of objects found as a result of the LIST operation. expected = %d, actual = %d", + len(bucketWithObj.ObjectMata.ExistingObjectIDs), len(objectNames)) + log.Println(err.Error()) + return err + } + + for _, objName := range objectNames { + if !bucketWithObj.ObjectMata.Exist(objName) { + err = fmt.Errorf("Invalid object key '%s' found in the result of the LIST operation. workerID = 0x%x", + objName, w.id) + log.Println(err.Error()) + return err + } + } + + w.st.AddListCount() + return nil +} + +func (w *Worker) Delete() error { + bucketWithObj := w.selectBucketWithObject() obj := bucketWithObj.ObjectMata.PopExistingRandomObject() if obj == nil { return nil } // Validation before delete - getBeforeBody, err := v.client.GetObject(bucketWithObj.BucketName, obj.Key) + getBeforeBody, err := w.client.GetObject(bucketWithObj.BucketName, obj.Key) if err != nil { var nsk *s3_client.NoSuchKey if errors.As(err, &nsk) { @@ -151,23 +180,23 @@ func (v *Worker) Delete() error { return err } defer getBeforeBody.Close() - err = pattern.Valid(v.id, bucketWithObj.BucketName, obj, getBeforeBody) + err = pattern.Valid(w.id, bucketWithObj.BucketName, obj, getBeforeBody) if err != nil { err = fmt.Errorf("Data validation error occurred before delete.\n%w", err) log.Println(err.Error()) return err } - v.st.AddGetForValidCount() + w.st.AddGetForValidCount() - err = v.client.DeleteObject(bucketWithObj.BucketName, obj.Key) + err = w.client.DeleteObject(bucketWithObj.BucketName, obj.Key) if err != nil { log.Println(err.Error()) return err } - v.st.AddDeleteCount() + w.st.AddDeleteCount() // Validation after delete - getAfterBody, err := v.client.GetObject(bucketWithObj.BucketName, obj.Key) + getAfterBody, err := w.client.GetObject(bucketWithObj.BucketName, obj.Key) if err != nil { var nsk *s3_client.NoSuchKey if !errors.As(err, &nsk) { @@ -185,6 +214,6 @@ func (v *Worker) Delete() error { return nil } -func (v *Worker) selectBucketWithObject() *BucketWithObject { - return v.BucketsWithObject[rand.Intn(len(v.BucketsWithObject))] +func (w *Worker) selectBucketWithObject() *BucketWithObject { + return w.BucketsWithObject[rand.Intn(len(w.BucketsWithObject))] } diff --git a/s3_client/s3_client.go b/s3_client/s3_client.go index 999ea0a..b48b828 100644 --- a/s3_client/s3_client.go +++ b/s3_client/s3_client.go @@ -73,12 +73,10 @@ func (s *S3Client) CreateBucket(bucketName string) error { } func (s *S3Client) ClearBucket(bucketName, prefix string) error { - var continuationToken *string = nil for { listRes, err := s.client.ListObjectsV2(context.Background(), &s3.ListObjectsV2Input{ - Bucket: &bucketName, - ContinuationToken: continuationToken, - Prefix: &prefix, + Bucket: &bucketName, + Prefix: &prefix, }) if err != nil { return err @@ -95,7 +93,6 @@ func (s *S3Client) ClearBucket(bucketName, prefix string) error { return err } } - continuationToken = listRes.NextContinuationToken } return nil } @@ -129,6 +126,30 @@ func (s *S3Client) GetObject(bucketName, key string) (io.ReadCloser, error) { return res.Body, err } +func (s *S3Client) ListObjects(bucketName, prefix string) ([]string, error) { + var continuationToken *string = nil + objectNames := make([]string, 0) + for { + listRes, err := s.client.ListObjectsV2(context.Background(), &s3.ListObjectsV2Input{ + Bucket: &bucketName, + ContinuationToken: continuationToken, + Prefix: &prefix, + }) + if err != nil { + return nil, err + } + for _, obj := range listRes.Contents { + objectNames = append(objectNames, *obj.Key) + } + + if listRes.NextContinuationToken == nil { + break + } + continuationToken = listRes.NextContinuationToken + } + return objectNames, nil +} + func (s *S3Client) DeleteObject(bucketName, key string) error { _, err := s.client.DeleteObject(context.Background(), &s3.DeleteObjectInput{ Bucket: &bucketName, diff --git a/stat/stat.go b/stat/stat.go index 41f5d35..ceb3f71 100644 --- a/stat/stat.go +++ b/stat/stat.go @@ -9,6 +9,7 @@ type Stat struct { putCount int64 getCount int64 getForValidCount int64 + listCount int64 deleteCount int64 } @@ -24,6 +25,10 @@ func (st *Stat) AddGetForValidCount() { atomic.AddInt64(&st.getForValidCount, 1) } +func (st *Stat) AddListCount() { + atomic.AddInt64(&st.listCount, 1) +} + func (st *Stat) AddDeleteCount() { atomic.AddInt64(&st.deleteCount, 1) } @@ -33,5 +38,6 @@ func (st *Stat) Report() { log.Printf("put count: %d\n", st.putCount) log.Printf("get count: %d\n", st.getCount) log.Printf("get (for validation) count: %d\n", st.getForValidCount) + log.Printf("list count: %d\n", st.listCount) log.Printf("delete count: %d\n", st.deleteCount) }