Skip to content

Commit 021042e

Browse files
authored
HDDS-14685. Create context for BucketOperationHandler (#9798)
1 parent 8d03843 commit 021042e

7 files changed

Lines changed: 156 additions & 115 deletions

File tree

hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/endpoint/BucketAclHandler.java

Lines changed: 17 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,6 @@
4545
import org.apache.hadoop.ozone.s3.exception.S3ErrorTable;
4646
import org.apache.hadoop.ozone.s3.util.S3Consts.QueryParams;
4747
import org.apache.hadoop.ozone.security.acl.IAccessAuthorizer;
48-
import org.apache.hadoop.util.Time;
4948
import org.apache.http.HttpStatus;
5049
import org.slf4j.Logger;
5150
import org.slf4j.LoggerFactory;
@@ -57,7 +56,7 @@
5756
* This handler extends EndpointBase to inherit all required functionality
5857
* (configuration, headers, request context, audit logging, metrics, etc.).
5958
*/
60-
public class BucketAclHandler extends EndpointBase implements BucketOperationHandler {
59+
public class BucketAclHandler extends BucketOperationHandler {
6160

6261
private static final Logger LOG = LoggerFactory.getLogger(BucketAclHandler.class);
6362

@@ -75,15 +74,14 @@ private boolean shouldHandle() {
7574
* see: https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketAcl.html
7675
*/
7776
@Override
78-
public Response handleGetRequest(String bucketName)
77+
Response handleGetRequest(S3RequestContext context, String bucketName)
7978
throws IOException, OS3Exception {
8079

8180
if (!shouldHandle()) {
8281
return null; // Not responsible for this request
8382
}
8483

85-
long startNanos = Time.monotonicNowNanos();
86-
S3GAction s3GAction = S3GAction.GET_ACL;
84+
context.setAction(S3GAction.GET_ACL);
8785

8886
try {
8987
OzoneBucket bucket = getBucket(bucketName);
@@ -107,12 +105,12 @@ public Response handleGetRequest(String bucketName)
107105
result.setAclList(
108106
new S3BucketAcl.AccessControlList(grantList));
109107

110-
getMetrics().updateGetAclSuccessStats(startNanos);
111-
auditReadSuccess(s3GAction);
108+
getMetrics().updateGetAclSuccessStats(context.getStartNanos());
109+
auditReadSuccess(context.getAction());
112110
return Response.ok(result, MediaType.APPLICATION_XML_TYPE).build();
113111
} catch (OMException ex) {
114-
getMetrics().updateGetAclFailureStats(startNanos);
115-
auditReadFailure(s3GAction, ex);
112+
getMetrics().updateGetAclFailureStats(context.getStartNanos());
113+
auditReadFailure(context.getAction(), ex);
116114
if (ex.getResult() == ResultCodes.BUCKET_NOT_FOUND) {
117115
throw newError(S3ErrorTable.NO_SUCH_BUCKET, bucketName, ex);
118116
} else if (isAccessDenied(ex)) {
@@ -121,8 +119,8 @@ public Response handleGetRequest(String bucketName)
121119
throw newError(S3ErrorTable.INTERNAL_ERROR, bucketName, ex);
122120
}
123121
} catch (OS3Exception ex) {
124-
getMetrics().updateGetAclFailureStats(startNanos);
125-
auditReadFailure(s3GAction, ex);
122+
getMetrics().updateGetAclFailureStats(context.getStartNanos());
123+
auditReadFailure(context.getAction(), ex);
126124
throw ex;
127125
}
128126
}
@@ -133,15 +131,14 @@ public Response handleGetRequest(String bucketName)
133131
* see: https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketAcl.html
134132
*/
135133
@Override
136-
public Response handlePutRequest(String bucketName, InputStream body)
134+
Response handlePutRequest(S3RequestContext context, String bucketName, InputStream body)
137135
throws IOException, OS3Exception {
138136

139137
if (!shouldHandle()) {
140138
return null; // Not responsible for this request
141139
}
142140

143-
long startNanos = Time.monotonicNowNanos();
144-
S3GAction s3GAction = S3GAction.PUT_ACL;
141+
context.setAction(S3GAction.PUT_ACL);
145142

146143
String grantReads = getHeaders().getHeaderString(S3Acl.GRANT_READ);
147144
String grantWrites = getHeaders().getHeaderString(S3Acl.GRANT_WRITE);
@@ -226,22 +223,22 @@ public Response handlePutRequest(String bucketName, InputStream body)
226223
volume.addAcl(acl);
227224
}
228225

229-
getMetrics().updatePutAclSuccessStats(startNanos);
230-
auditWriteSuccess(s3GAction);
226+
getMetrics().updatePutAclSuccessStats(context.getStartNanos());
227+
auditWriteSuccess(context.getAction());
231228
return Response.status(HttpStatus.SC_OK).build();
232229

233230
} catch (OMException exception) {
234-
getMetrics().updatePutAclFailureStats(startNanos);
235-
auditWriteFailure(s3GAction, exception);
231+
getMetrics().updatePutAclFailureStats(context.getStartNanos());
232+
auditWriteFailure(context.getAction(), exception);
236233
if (exception.getResult() == ResultCodes.BUCKET_NOT_FOUND) {
237234
throw newError(S3ErrorTable.NO_SUCH_BUCKET, bucketName, exception);
238235
} else if (isAccessDenied(exception)) {
239236
throw newError(S3ErrorTable.ACCESS_DENIED, bucketName, exception);
240237
}
241238
throw exception;
242239
} catch (OS3Exception ex) {
243-
getMetrics().updatePutAclFailureStats(startNanos);
244-
auditWriteFailure(s3GAction, ex);
240+
getMetrics().updatePutAclFailureStats(context.getStartNanos());
241+
auditWriteFailure(context.getAction(), ex);
245242
throw ex;
246243
}
247244
}

hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/endpoint/BucketCrudHandler.java

Lines changed: 15 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@
2828
import org.apache.hadoop.ozone.s3.exception.OS3Exception;
2929
import org.apache.hadoop.ozone.s3.exception.S3ErrorTable;
3030
import org.apache.hadoop.ozone.s3.util.S3Consts.QueryParams;
31-
import org.apache.hadoop.util.Time;
3231
import org.apache.http.HttpStatus;
3332

3433
/**
@@ -43,7 +42,7 @@
4342
* This handler extends EndpointBase to inherit all required functionality
4443
* (configuration, headers, request context, audit logging, metrics, etc.).
4544
*/
46-
public class BucketCrudHandler extends EndpointBase implements BucketOperationHandler {
45+
public class BucketCrudHandler extends BucketOperationHandler {
4746

4847
/**
4948
* Handle only plain PUT bucket (create bucket), not subresources.
@@ -58,31 +57,30 @@ && queryParams().get(QueryParams.UPLOADS) == null
5857
* Handle PUT /{bucket} for bucket creation.
5958
*/
6059
@Override
61-
public Response handlePutRequest(String bucketName, InputStream body)
60+
Response handlePutRequest(S3RequestContext context, String bucketName, InputStream body)
6261
throws IOException, OS3Exception {
6362

6463
if (!shouldHandle()) {
6564
return null;
6665
}
6766

68-
long startNanos = Time.monotonicNowNanos();
69-
S3GAction s3GAction = S3GAction.CREATE_BUCKET;
67+
context.setAction(S3GAction.CREATE_BUCKET);
7068

7169
try {
7270
String location = createS3Bucket(bucketName);
73-
auditWriteSuccess(s3GAction);
74-
getMetrics().updateCreateBucketSuccessStats(startNanos);
71+
auditWriteSuccess(context.getAction());
72+
getMetrics().updateCreateBucketSuccessStats(context.getStartNanos());
7573
return Response.status(HttpStatus.SC_OK).header("Location", location)
7674
.build();
7775
} catch (OMException exception) {
78-
auditWriteFailure(s3GAction, exception);
79-
getMetrics().updateCreateBucketFailureStats(startNanos);
76+
auditWriteFailure(context.getAction(), exception);
77+
getMetrics().updateCreateBucketFailureStats(context.getStartNanos());
8078
if (exception.getResult() == OMException.ResultCodes.INVALID_BUCKET_NAME) {
8179
throw newError(S3ErrorTable.INVALID_BUCKET_NAME, bucketName, exception);
8280
}
8381
throw exception;
8482
} catch (Exception ex) {
85-
auditWriteFailure(s3GAction, ex);
83+
auditWriteFailure(context.getAction(), ex);
8684
throw ex;
8785
}
8886
}
@@ -91,15 +89,14 @@ public Response handlePutRequest(String bucketName, InputStream body)
9189
* Handle DELETE /{bucket} for bucket deletion.
9290
*/
9391
@Override
94-
public Response handleDeleteRequest(String bucketName)
92+
Response handleDeleteRequest(S3RequestContext context, String bucketName)
9593
throws IOException, OS3Exception {
9694

9795
if (!shouldHandle()) {
9896
return null;
9997
}
10098

101-
long startNanos = Time.monotonicNowNanos();
102-
S3GAction s3GAction = S3GAction.DELETE_BUCKET;
99+
context.setAction(S3GAction.DELETE_BUCKET);
103100

104101
try {
105102
if (S3Owner.hasBucketOwnershipVerificationConditions(getHeaders())) {
@@ -108,8 +105,8 @@ public Response handleDeleteRequest(String bucketName)
108105
}
109106
deleteS3Bucket(bucketName);
110107
} catch (OMException ex) {
111-
auditWriteFailure(s3GAction, ex);
112-
getMetrics().updateDeleteBucketFailureStats(startNanos);
108+
auditWriteFailure(context.getAction(), ex);
109+
getMetrics().updateDeleteBucketFailureStats(context.getStartNanos());
113110
if (ex.getResult() == OMException.ResultCodes.BUCKET_NOT_EMPTY) {
114111
throw newError(S3ErrorTable.BUCKET_NOT_EMPTY, bucketName, ex);
115112
} else if (ex.getResult() == OMException.ResultCodes.BUCKET_NOT_FOUND) {
@@ -120,12 +117,12 @@ public Response handleDeleteRequest(String bucketName)
120117
throw ex;
121118
}
122119
} catch (Exception ex) {
123-
auditWriteFailure(s3GAction, ex);
120+
auditWriteFailure(context.getAction(), ex);
124121
throw ex;
125122
}
126123

127-
auditWriteSuccess(s3GAction);
128-
getMetrics().updateDeleteBucketSuccessStats(startNanos);
124+
auditWriteSuccess(context.getAction());
125+
getMetrics().updateDeleteBucketSuccessStats(context.getStartNanos());
129126
return Response
130127
.status(HttpStatus.SC_NO_CONTENT)
131128
.build();

hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/endpoint/BucketEndpoint.java

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -97,13 +97,15 @@ public class BucketEndpoint extends EndpointBase {
9797
public Response get(
9898
@PathParam(BUCKET) String bucketName
9999
) throws OS3Exception, IOException {
100-
long startNanos = Time.monotonicNowNanos();
101-
S3GAction s3GAction = S3GAction.GET_BUCKET;
102-
PerformanceStringBuilder perf = new PerformanceStringBuilder();
100+
S3RequestContext context = new S3RequestContext(this, S3GAction.GET_BUCKET);
101+
102+
long startNanos = context.getStartNanos();
103+
S3GAction s3GAction = context.getAction();
104+
PerformanceStringBuilder perf = context.getPerf();
103105

104106
// Chain of responsibility: let each handler try to handle the request
105107
for (BucketOperationHandler handler : handlers) {
106-
Response response = handler.handleGetRequest(bucketName);
108+
Response response = handler.handleGetRequest(context, bucketName);
107109
if (response != null) {
108110
return response; // Handler handled the request
109111
}
@@ -299,9 +301,11 @@ public Response put(
299301
InputStream body
300302
) throws IOException, OS3Exception {
301303

304+
S3RequestContext context = new S3RequestContext(this, S3GAction.CREATE_BUCKET);
305+
302306
// Chain of responsibility: let each handler try to handle the request
303307
for (BucketOperationHandler handler : handlers) {
304-
Response response = handler.handlePutRequest(bucketName, body);
308+
Response response = handler.handlePutRequest(context, bucketName, body);
305309
if (response != null) {
306310
return response; // Handler handled the request
307311
}
@@ -400,8 +404,10 @@ public Response head(@PathParam(BUCKET) String bucketName)
400404
@DELETE
401405
public Response delete(@PathParam(BUCKET) String bucketName)
402406
throws IOException, OS3Exception {
407+
S3RequestContext context = new S3RequestContext(this, S3GAction.DELETE_BUCKET);
408+
403409
for (BucketOperationHandler handler : handlers) {
404-
Response response = handler.handleDeleteRequest(bucketName);
410+
Response response = handler.handleDeleteRequest(context, bucketName);
405411
if (response != null) {
406412
return response;
407413
}
@@ -507,7 +513,7 @@ protected void init() {
507513
addHandler(new BucketCrudHandler());
508514
}
509515

510-
private <T extends EndpointBase & BucketOperationHandler> void addHandler(T handler) {
516+
private void addHandler(BucketOperationHandler handler) {
511517
copyDependenciesTo(handler);
512518
handlers.add(handler);
513519
}

hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/endpoint/BucketOperationHandler.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
* Implementations should extend EndpointBase to inherit all required functionality
3131
* (configuration, headers, request context, audit logging, metrics, etc.).
3232
*/
33-
public interface BucketOperationHandler {
33+
abstract class BucketOperationHandler extends EndpointBase {
3434

3535
/**
3636
* Handle the bucket PUT operation if this handler is responsible for it.
@@ -43,7 +43,7 @@ public interface BucketOperationHandler {
4343
* @throws IOException if an I/O error occurs
4444
* @throws OS3Exception if an S3-specific error occurs
4545
*/
46-
default Response handlePutRequest(String bucketName, InputStream body)
46+
Response handlePutRequest(S3RequestContext context, String bucketName, InputStream body)
4747
throws IOException, OS3Exception {
4848
return null;
4949
}
@@ -53,17 +53,18 @@ default Response handlePutRequest(String bucketName, InputStream body)
5353
* The handler inspects the request (query parameters, headers, etc.) to determine
5454
* if it should handle the request.
5555
*
56+
* @param context
5657
* @param bucketName the name of the bucket
5758
* @return Response if this handler handles the request, null otherwise
5859
* @throws IOException if an I/O error occurs
5960
* @throws OS3Exception if an S3-specific error occurs
6061
*/
61-
default Response handleGetRequest(String bucketName)
62+
Response handleGetRequest(S3RequestContext context, String bucketName)
6263
throws IOException, OS3Exception {
6364
return null;
6465
}
6566

66-
default Response handleDeleteRequest(String bucketName)
67+
Response handleDeleteRequest(S3RequestContext context, String bucketName)
6768
throws IOException, OS3Exception {
6869
return null;
6970
}

hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/endpoint/ObjectEndpoint.java

Lines changed: 3 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,6 @@
4747
import static org.apache.hadoop.ozone.s3.util.S3Utils.wrapInQuotes;
4848

4949
import com.google.common.collect.ImmutableMap;
50-
import jakarta.annotation.Nullable;
5150
import java.io.EOFException;
5251
import java.io.IOException;
5352
import java.io.InputStream;
@@ -656,7 +655,7 @@ public Response delete(
656655
Response handleDeleteRequest(ObjectRequestContext context, String keyPath)
657656
throws IOException, OS3Exception {
658657

659-
final long startNanos = context.startNanos;
658+
final long startNanos = context.getStartNanos();
660659

661660
try {
662661
OzoneVolume volume = context.getVolume();
@@ -1130,67 +1129,26 @@ private CopyObjectResponse copyObject(OzoneVolume volume,
11301129
}
11311130

11321131
/** Request context shared among {@code ObjectOperationHandler}s. */
1133-
final class ObjectRequestContext {
1132+
final class ObjectRequestContext extends S3RequestContext {
11341133
private final String bucketName;
1135-
private final long startNanos;
1136-
private final PerformanceStringBuilder perf;
1137-
private S3GAction action;
1138-
private OzoneVolume volume;
11391134
private OzoneBucket bucket;
11401135

11411136
/** @param action best guess on action based on request method, may be refined later by handlers */
11421137
ObjectRequestContext(S3GAction action, String bucketName) {
1143-
this.action = action;
1138+
super(ObjectEndpoint.this, action);
11441139
this.bucketName = bucketName;
1145-
this.startNanos = Time.monotonicNowNanos();
1146-
this.perf = new PerformanceStringBuilder();
1147-
}
1148-
1149-
long getStartNanos() {
1150-
return startNanos;
1151-
}
1152-
1153-
PerformanceStringBuilder getPerf() {
1154-
return perf;
11551140
}
11561141

11571142
String getBucketName() {
11581143
return bucketName;
11591144
}
11601145

1161-
OzoneVolume getVolume() throws IOException {
1162-
if (volume == null) {
1163-
volume = ObjectEndpoint.this.getVolume();
1164-
}
1165-
return volume;
1166-
}
1167-
11681146
OzoneBucket getBucket() throws IOException {
11691147
if (bucket == null) {
11701148
bucket = getVolume().getBucket(bucketName);
11711149
}
11721150
return bucket;
11731151
}
11741152

1175-
S3GAction getAction() {
1176-
return action;
1177-
}
1178-
1179-
void setAction(S3GAction action) {
1180-
this.action = action;
1181-
}
1182-
1183-
/**
1184-
* This method should be called by each handler with the {@code S3GAction} decided based on request parameters,
1185-
* {@code null} if it does not handle the request. {@code action} is stored, if not null, for use in audit logging.
1186-
* @param a action as determined by handler
1187-
* @return true if handler should ignore the request (i.e. if {@code null} is passed) */
1188-
boolean ignore(@Nullable S3GAction a) {
1189-
final boolean ignore = a == null;
1190-
if (!ignore) {
1191-
setAction(a);
1192-
}
1193-
return ignore;
1194-
}
11951153
}
11961154
}

0 commit comments

Comments
 (0)