1919
2020final class GoogleCloudStorageOperationsStats {
2121
22+ private final String bucketName ;
23+ private final StatsTracker tracker ;
24+
25+ GoogleCloudStorageOperationsStats (String bucketName , boolean isStateless ) {
26+ this .bucketName = bucketName ;
27+ if (isStateless ) {
28+ this .tracker = new ServerlessTracker (bucketName );
29+ } else {
30+ this .tracker = new StatefulTracker ();
31+ }
32+ }
33+
34+ GoogleCloudStorageOperationsStats (String bucketName ) {
35+ this (bucketName , false );
36+ }
37+
38+ public String bucketName () {
39+ return bucketName ;
40+ }
41+
42+ public StatsTracker tracker () {
43+ return tracker ;
44+ }
45+
46+ public enum Operation {
47+ GET_OBJECT ("GetObject" ),
48+ LIST_OBJECTS ("ListObjects" ),
49+ INSERT_OBJECT ("InsertObject" );
50+
51+ private final String key ;
52+
53+ Operation (String key ) {
54+ this .key = key ;
55+ }
56+
57+ public String key () {
58+ return key ;
59+ }
60+ }
61+
62+ sealed interface StatsTracker permits ServerlessTracker , StatefulTracker {
63+ void trackRequest (OperationPurpose purpose , Operation operation );
64+
65+ void trackOperation (OperationPurpose purpose , Operation operation );
66+
67+ Map <String , BlobStoreActionStats > toMap ();
68+
69+ default void trackOperationAndRequest (OperationPurpose purpose , Operation operation ) {
70+ trackOperation (purpose , operation );
71+ trackRequest (purpose , operation );
72+ }
73+ }
74+
75+ /**
76+ * Stateful tracker is single dimension: Operation only. The OperationPurpose is ignored.
77+ */
78+ static final class StatefulTracker implements StatsTracker {
79+
80+ private final EnumMap <Operation , Counters > counters ;
81+
82+ StatefulTracker () {
83+ this .counters = new EnumMap <>(Operation .class );
84+ for (var operation : Operation .values ()) {
85+ counters .put (operation , new Counters (operation .key ()));
86+ }
87+ }
88+
89+ @ Override
90+ public void trackRequest (OperationPurpose purpose , Operation operation ) {
91+ // dont track requests, only operations
92+ }
93+
94+ @ Override
95+ public void trackOperation (OperationPurpose purpose , Operation operation ) {
96+ counters .get (operation ).operations ().add (1 );
97+ }
98+
99+ @ Override
100+ public Map <String , BlobStoreActionStats > toMap () {
101+ return counters .values ().stream ().collect (Collectors .toUnmodifiableMap (Counters ::name , (c ) -> {
102+ var ops = c .operations ().sum ();
103+ return new BlobStoreActionStats (ops , ops );
104+ }));
105+ }
106+
107+ }
108+
22109 /**
23- * Every operation purpose and operation has a set of counters.
24- * Represented by {@code Map<Purpose,Map<Operation,Counters>>}
110+ * Serverless tracker is 2-dimensional: OperationPurpose and Operations.
111+ * Every combination of these has own set of counters: number of operations and number of http requests.
112+ * A single operation might have multiple HTTP requests, for example a single ResumableUpload operation
113+ * can perform a series of HTTP requests with size up to {@link GoogleCloudStorageBlobStore#SDK_DEFAULT_CHUNK_SIZE}.
25114 * <pre>
26115 * {@code
27116 * | Purpose | Operation | OperationsCnt | RequestCnt |
@@ -35,63 +124,52 @@ final class GoogleCloudStorageOperationsStats {
35124 * }
36125 * </pre>
37126 */
38- private final EnumMap < OperationPurpose , EnumMap < Operation , Counters >> counters ;
39- private final String bucketName ;
127+ static final class ServerlessTracker implements StatsTracker {
128+ private final EnumMap < OperationPurpose , EnumMap < Operation , Counters >> counters ;
40129
41- GoogleCloudStorageOperationsStats (String bucketName ) {
42- this .bucketName = bucketName ;
43- this .counters = new EnumMap <>(OperationPurpose .class );
44- for (var purpose : OperationPurpose .values ()) {
45- var operations = new EnumMap <Operation , Counters >(Operation .class );
46- for (var operation : Operation .values ()) {
47- operations .put (operation , new Counters (purpose , operation ));
130+ ServerlessTracker (String bucketName ) {
131+ this .counters = new EnumMap <>(OperationPurpose .class );
132+ for (var purpose : OperationPurpose .values ()) {
133+ var operations = new EnumMap <Operation , Counters >(Operation .class );
134+ for (var operation : Operation .values ()) {
135+ operations .put (operation , new Counters (purpose .getKey () + "_" + operation .key ()));
136+ }
137+ counters .put (purpose , operations );
48138 }
49- counters .put (purpose , operations );
50139 }
51- }
52140
53- public String bucketName () {
54- return bucketName ;
55- }
56-
57- void trackOperation (OperationPurpose purpose , Operation operation ) {
58- counters .get (purpose ).get (operation ).operations .add (1 );
59- }
60-
61- void trackRequest (OperationPurpose purpose , Operation operation ) {
62- counters .get (purpose ).get (operation ).requests .add (1 );
63- }
64-
65- void trackRequestAndOperation (OperationPurpose purpose , Operation operation ) {
66- var c = counters .get (purpose ).get (operation );
67- c .requests .add (1 );
68- c .operations .add (1 );
69- }
70-
71- Map <String , BlobStoreActionStats > toMap () {
72- return counters .values ()
73- .stream ()
74- .flatMap (ops -> ops .values ().stream ())
75- .collect (Collectors .toUnmodifiableMap (Counters ::name , (c ) -> new BlobStoreActionStats (c .operations .sum (), c .requests .sum ())));
76- }
141+ @ Override
142+ public void trackOperation (OperationPurpose purpose , Operation operation ) {
143+ counters .get (purpose ).get (operation ).operations .add (1 );
144+ }
77145
78- public enum Operation {
79- GET_METADATA ("GetMetadata" ),
80- GET_OBJECT ("GetObject" ),
81- LIST_OBJECTS ("ListObjects" ),
82- MULTIPART_UPLOAD ("MultipartUpload" ),
83- RESUMABLE_UPLOAD ("ResumableUpload" );
146+ @ Override
147+ public void trackRequest (OperationPurpose purpose , Operation operation ) {
148+ counters .get (purpose ).get (operation ).requests .add (1 );
149+ }
84150
85- final String name ;
151+ @ Override
152+ public void trackOperationAndRequest (OperationPurpose purpose , Operation operation ) {
153+ var c = counters .get (purpose ).get (operation );
154+ c .requests .add (1 );
155+ c .operations .add (1 );
156+ }
86157
87- Operation (String name ) {
88- this .name = name ;
158+ @ Override
159+ public Map <String , BlobStoreActionStats > toMap () {
160+ return counters .values ()
161+ .stream ()
162+ .flatMap (ops -> ops .values ().stream ())
163+ .collect (
164+ Collectors .toUnmodifiableMap (Counters ::name , (c ) -> new BlobStoreActionStats (c .operations .sum (), c .requests .sum ()))
165+ );
89166 }
167+
90168 }
91169
92170 private record Counters (String name , LongAdder operations , LongAdder requests ) {
93- Counters (OperationPurpose purpose , Operation operation ) {
94- this (purpose . name () + '_' + operation . name () , new LongAdder (), new LongAdder ());
171+ Counters (String name ) {
172+ this (name , new LongAdder (), new LongAdder ());
95173 }
96174 }
97175}
0 commit comments