io.grpc
grpc-testing
diff --git a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/OmUtils.java b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/OmUtils.java
index 82030669c93..11f176362a6 100644
--- a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/OmUtils.java
+++ b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/OmUtils.java
@@ -274,6 +274,7 @@ public static boolean isReadOnly(
case SetSafeMode:
case PrintCompactionLogDag:
case GetSnapshotInfo:
+ case GetServerDefaults:
return true;
case CreateVolume:
case SetVolumeProperty:
@@ -327,6 +328,7 @@ public static boolean isReadOnly(
case SetTimes:
case AbortExpiredMultiPartUploads:
case SetSnapshotProperty:
+ case QuotaRepair:
case UnknownCommand:
return false;
case EchoRPC:
diff --git a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/OzoneFsServerDefaults.java b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/OzoneFsServerDefaults.java
new file mode 100644
index 00000000000..782fa88e8d2
--- /dev/null
+++ b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/OzoneFsServerDefaults.java
@@ -0,0 +1,59 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.hadoop.ozone;
+
+import org.apache.hadoop.fs.FsServerDefaults;
+import org.apache.hadoop.hdds.annotation.InterfaceAudience;
+import org.apache.hadoop.hdds.annotation.InterfaceStability;
+
+import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.FsServerDefaultsProto;
+import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.FsServerDefaultsProto.Builder;
+
+
+/****************************************************
+ * Provides server default configuration values to clients.
+ *
+ ****************************************************/
+@InterfaceAudience.Public
+@InterfaceStability.Evolving
+public class OzoneFsServerDefaults extends FsServerDefaults {
+
+ public OzoneFsServerDefaults() {
+ }
+
+ public OzoneFsServerDefaults(String keyProviderUri) {
+ super(0L, 0, 0, (short)0, 0, false, 0L, null, keyProviderUri);
+ }
+
+ public FsServerDefaultsProto getProtobuf() {
+ Builder builder = FsServerDefaultsProto.newBuilder();
+ if (getKeyProviderUri() != null) {
+ builder.setKeyProviderUri(getKeyProviderUri());
+ }
+ return builder.build();
+ }
+
+ public static OzoneFsServerDefaults getFromProtobuf(
+ FsServerDefaultsProto serverDefaults) {
+ String keyProviderUri = null;
+ if (serverDefaults.hasKeyProviderUri()) {
+ keyProviderUri = serverDefaults.getKeyProviderUri();
+ }
+ return new OzoneFsServerDefaults(keyProviderUri);
+ }
+}
diff --git a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/protocol/OzoneManagerProtocol.java b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/protocol/OzoneManagerProtocol.java
index 5f592663dad..45922c107cb 100644
--- a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/protocol/OzoneManagerProtocol.java
+++ b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/protocol/OzoneManagerProtocol.java
@@ -28,6 +28,7 @@
import org.apache.hadoop.fs.SafeModeAction;
import org.apache.hadoop.hdds.scm.container.common.helpers.ExcludeList;
import org.apache.hadoop.ozone.OzoneAcl;
+import org.apache.hadoop.ozone.OzoneFsServerDefaults;
import org.apache.hadoop.ozone.om.IOmMetadataReader;
import org.apache.hadoop.ozone.om.OMConfigKeys;
import org.apache.hadoop.ozone.om.exceptions.OMException;
@@ -1178,4 +1179,12 @@ void setTimes(OmKeyArgs keyArgs, long mtime, long atime)
*/
boolean setSafeMode(SafeModeAction action, boolean isChecked)
throws IOException;
+
+ /**
+ * Get server default configurations.
+ *
+ * @return OzoneFsServerDefaults some default configurations from server.
+ * @throws IOException
+ */
+ OzoneFsServerDefaults getServerDefaults() throws IOException;
}
diff --git a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/protocolPB/OzoneManagerProtocolClientSideTranslatorPB.java b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/protocolPB/OzoneManagerProtocolClientSideTranslatorPB.java
index 9a965b7c3d0..f70beed5f25 100644
--- a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/protocolPB/OzoneManagerProtocolClientSideTranslatorPB.java
+++ b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/protocolPB/OzoneManagerProtocolClientSideTranslatorPB.java
@@ -41,6 +41,7 @@
import org.apache.hadoop.ipc.CallerContext;
import org.apache.hadoop.ozone.ClientVersion;
import org.apache.hadoop.ozone.OzoneAcl;
+import org.apache.hadoop.ozone.OzoneFsServerDefaults;
import org.apache.hadoop.ozone.om.exceptions.OMException;
import org.apache.hadoop.ozone.om.helpers.BasicOmKeyInfo;
import org.apache.hadoop.ozone.om.helpers.ErrorInfo;
@@ -197,6 +198,8 @@
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.S3Authentication;
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.S3Secret;
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.SafeMode;
+import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.ServerDefaultsRequest;
+import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.ServerDefaultsResponse;
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.ServiceListRequest;
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.ServiceListResponse;
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.SetAclRequest;
@@ -2644,6 +2647,22 @@ public boolean setSafeMode(SafeModeAction action, boolean isChecked)
return setSafeModeResponse.getResponse();
}
+ @Override
+ public OzoneFsServerDefaults getServerDefaults()
+ throws IOException {
+ ServerDefaultsRequest serverDefaultsRequest =
+ ServerDefaultsRequest.newBuilder().build();
+
+ OMRequest omRequest = createOMRequest(Type.GetServerDefaults)
+ .setServerDefaultsRequest(serverDefaultsRequest).build();
+
+ ServerDefaultsResponse serverDefaultsResponse =
+ handleError(submitRequest(omRequest)).getServerDefaultsResponse();
+
+ return OzoneFsServerDefaults.getFromProtobuf(
+ serverDefaultsResponse.getServerDefaults());
+ }
+
private SafeMode toProtoBuf(SafeModeAction action) {
switch (action) {
case ENTER:
diff --git a/hadoop-ozone/csi/pom.xml b/hadoop-ozone/csi/pom.xml
index 04c153f3988..a0565d7e890 100644
--- a/hadoop-ozone/csi/pom.xml
+++ b/hadoop-ozone/csi/pom.xml
@@ -33,6 +33,10 @@ http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+ org.apache.ozone
+ hdds-common
+
com.google.protobuf
protobuf-java-util
@@ -70,6 +74,15 @@ http://maven.apache.org/xsd/maven-4.0.0.xsd">
org.apache.ozone
hdds-server-framework
+
+ org.apache.ozone
+ ozone-common
+
+
+
+ commons-io
+ commons-io
+
com.google.code.findbugs
jsr305
@@ -90,6 +103,14 @@ http://maven.apache.org/xsd/maven-4.0.0.xsd">
io.grpc
grpc-netty
+
+ io.netty
+ netty-transport
+
+
+ io.netty
+ netty-transport-classes-epoll
+
io.netty
netty-transport-native-epoll
@@ -111,10 +132,24 @@ http://maven.apache.org/xsd/maven-4.0.0.xsd">
ch.qos.reload4j
reload4j
+
+ org.slf4j
+ slf4j-api
+
org.slf4j
slf4j-reload4j
+
+ io.grpc
+ grpc-api
+
+
+ com.google.code.findbugs
+ jsr305
+
+
+
io.grpc
grpc-protobuf
@@ -133,6 +168,10 @@ http://maven.apache.org/xsd/maven-4.0.0.xsd">
io.grpc
grpc-stub
+
+ info.picocli
+ picocli
+
org.apache.ozone
ozone-client
diff --git a/hadoop-ozone/dev-support/checks/acceptance.sh b/hadoop-ozone/dev-support/checks/acceptance.sh
index 1e16b277aff..3425f66605e 100755
--- a/hadoop-ozone/dev-support/checks/acceptance.sh
+++ b/hadoop-ozone/dev-support/checks/acceptance.sh
@@ -52,11 +52,6 @@ if [[ "${OZONE_ACCEPTANCE_SUITE}" == "s3a" ]]; then
download_hadoop_aws "${HADOOP_AWS_DIR}"
fi
-if [[ "${OZONE_ACCEPTANCE_TEST_TYPE}" == "robot" ]]; then
- install_virtualenv
- install_robot
-fi
-
export OZONE_ACCEPTANCE_SUITE OZONE_ACCEPTANCE_TEST_TYPE
cd "$DIST_DIR/compose" || exit 1
diff --git a/hadoop-ozone/dist/src/main/compose/common/grafana/dashboards/Datanode Chunk Read_Write Dashboard.json b/hadoop-ozone/dist/src/main/compose/common/grafana/dashboards/Datanode Chunk Read_Write Dashboard.json
index 104382f9850..44749f902cf 100644
--- a/hadoop-ozone/dist/src/main/compose/common/grafana/dashboards/Datanode Chunk Read_Write Dashboard.json
+++ b/hadoop-ozone/dist/src/main/compose/common/grafana/dashboards/Datanode Chunk Read_Write Dashboard.json
@@ -1,7 +1,6 @@
{
"__inputs": [
{
- "name": "DS_PROMETHEUS",
"label": "prometheus",
"description": "",
"type": "datasource",
@@ -15,7 +14,7 @@
"type": "grafana",
"id": "grafana",
"name": "Grafana",
- "version": "10.4.2"
+ "version": "11.1.4"
},
{
"type": "datasource",
@@ -65,8 +64,7 @@
},
{
"datasource": {
- "type": "prometheus",
- "uid": "${DS_PROMETHEUS}"
+ "type": "prometheus"
},
"fieldConfig": {
"defaults": {
@@ -145,15 +143,18 @@
"targets": [
{
"datasource": {
- "type": "prometheus",
- "uid": "${DS_PROMETHEUS}"
+ "type": "prometheus"
},
- "editorMode": "code",
- "expr": "rate(volume_io_stats_read_bytes[$__rate_interval])",
+ "disableTextWrap": false,
+ "editorMode": "builder",
+ "expr": "rate(volume_io_stats_read_bytes[$__interval])",
+ "fullMetaSearch": false,
+ "includeNullMetadata": true,
"instant": false,
"legendFormat": "Datanode={{label_name}} Volume={{storagedirectory}}",
"range": true,
- "refId": "A"
+ "refId": "A",
+ "useBackend": false
}
],
"title": "Data read per Volume",
@@ -161,8 +162,7 @@
},
{
"datasource": {
- "type": "prometheus",
- "uid": "${DS_PROMETHEUS}"
+ "type": "prometheus"
},
"fieldConfig": {
"defaults": {
@@ -240,15 +240,18 @@
"targets": [
{
"datasource": {
- "type": "prometheus",
- "uid": "${DS_PROMETHEUS}"
+ "type": "prometheus"
},
- "editorMode": "code",
- "expr": "rate(volume_io_stats_read_op_count[$__rate_interval])",
+ "disableTextWrap": false,
+ "editorMode": "builder",
+ "expr": "rate(volume_io_stats_read_op_count[$__interval])",
+ "fullMetaSearch": false,
+ "includeNullMetadata": true,
"instant": false,
"legendFormat": "Datanode={{hostname}} Volume={{storagedirectory}}",
"range": true,
- "refId": "A"
+ "refId": "A",
+ "useBackend": false
}
],
"title": "Read Ops",
@@ -256,8 +259,7 @@
},
{
"datasource": {
- "type": "prometheus",
- "uid": "${DS_PROMETHEUS}"
+ "type": "prometheus"
},
"fieldConfig": {
"defaults": {
@@ -336,15 +338,18 @@
"targets": [
{
"datasource": {
- "type": "prometheus",
- "uid": "${DS_PROMETHEUS}"
+ "type": "prometheus"
},
- "editorMode": "code",
- "expr": "rate(volume_io_stats_write_bytes[$__rate_interval])",
+ "disableTextWrap": false,
+ "editorMode": "builder",
+ "expr": "rate(volume_io_stats_write_bytes[$__interval])",
+ "fullMetaSearch": false,
+ "includeNullMetadata": true,
"instant": false,
"legendFormat": "Datanode={{label_name}} Volume={{storagedirectory}}",
"range": true,
- "refId": "A"
+ "refId": "A",
+ "useBackend": false
}
],
"title": "Data write per Volume",
@@ -352,8 +357,7 @@
},
{
"datasource": {
- "type": "prometheus",
- "uid": "${DS_PROMETHEUS}"
+ "type": "prometheus"
},
"fieldConfig": {
"defaults": {
@@ -431,15 +435,18 @@
"targets": [
{
"datasource": {
- "type": "prometheus",
- "uid": "${DS_PROMETHEUS}"
+ "type": "prometheus"
},
- "editorMode": "code",
- "expr": "rate(volume_io_stats_write_op_count[$__rate_interval])",
+ "disableTextWrap": false,
+ "editorMode": "builder",
+ "expr": "rate(volume_io_stats_write_op_count[$__interval])",
+ "fullMetaSearch": false,
+ "includeNullMetadata": true,
"instant": false,
"legendFormat": "Datanode={{hostname}} Volume={{storagedirectory}}",
"range": true,
- "refId": "A"
+ "refId": "A",
+ "useBackend": false
}
],
"title": "Write Ops",
@@ -460,8 +467,7 @@
},
{
"datasource": {
- "type": "prometheus",
- "uid": "${DS_PROMETHEUS}"
+ "type": "prometheus"
},
"fieldConfig": {
"defaults": {
@@ -540,15 +546,18 @@
"targets": [
{
"datasource": {
- "type": "prometheus",
- "uid": "${DS_PROMETHEUS}"
+ "type": "prometheus"
},
- "editorMode": "code",
- "expr": "rate(storage_container_metrics_bytes_write_chunk[$__rate_interval])",
+ "disableTextWrap": false,
+ "editorMode": "builder",
+ "expr": "rate(storage_container_metrics_bytes_write_chunk[$__interval])",
+ "fullMetaSearch": false,
+ "includeNullMetadata": true,
"instant": false,
"legendFormat": "Datanode={{hostname}}",
"range": true,
- "refId": "A"
+ "refId": "A",
+ "useBackend": false
}
],
"title": "Write Chunk Traffic",
@@ -556,8 +565,7 @@
},
{
"datasource": {
- "type": "prometheus",
- "uid": "${DS_PROMETHEUS}"
+ "type": "prometheus"
},
"fieldConfig": {
"defaults": {
@@ -636,15 +644,18 @@
"targets": [
{
"datasource": {
- "type": "prometheus",
- "uid": "${DS_PROMETHEUS}"
+ "type": "prometheus"
},
- "editorMode": "code",
- "expr": "sum(rate(storage_container_metrics_bytes_write_chunk[$__rate_interval]))",
+ "disableTextWrap": false,
+ "editorMode": "builder",
+ "expr": "sum(rate(storage_container_metrics_bytes_write_chunk[$__interval]))",
+ "fullMetaSearch": false,
+ "includeNullMetadata": true,
"instant": false,
"legendFormat": "Datanode={{hostname}}",
"range": true,
- "refId": "A"
+ "refId": "A",
+ "useBackend": false
}
],
"title": "Total Write Chunk Traffic",
@@ -652,8 +663,7 @@
},
{
"datasource": {
- "type": "prometheus",
- "uid": "${DS_PROMETHEUS}"
+ "type": "prometheus"
},
"fieldConfig": {
"defaults": {
@@ -731,15 +741,18 @@
"targets": [
{
"datasource": {
- "type": "prometheus",
- "uid": "${DS_PROMETHEUS}"
+ "type": "prometheus"
},
- "editorMode": "code",
- "expr": "rate(storage_container_metrics_num_write_chunk[$__rate_interval])",
+ "disableTextWrap": false,
+ "editorMode": "builder",
+ "expr": "rate(storage_container_metrics_num_write_chunk[$__interval])",
+ "fullMetaSearch": false,
+ "includeNullMetadata": true,
"instant": false,
"legendFormat": "Datanode={{hostname}}",
"range": true,
- "refId": "A"
+ "refId": "A",
+ "useBackend": false
}
],
"title": "Write Chunks Ops",
@@ -747,8 +760,7 @@
},
{
"datasource": {
- "type": "prometheus",
- "uid": "${DS_PROMETHEUS}"
+ "type": "prometheus"
},
"fieldConfig": {
"defaults": {
@@ -826,15 +838,18 @@
"targets": [
{
"datasource": {
- "type": "prometheus",
- "uid": "${DS_PROMETHEUS}"
+ "type": "prometheus"
},
- "editorMode": "code",
- "expr": "rate(storage_container_metrics_bytes_put_block[$__rate_interval])",
+ "disableTextWrap": false,
+ "editorMode": "builder",
+ "expr": "rate(storage_container_metrics_bytes_put_block[$__interval])",
+ "fullMetaSearch": false,
+ "includeNullMetadata": true,
"instant": false,
"legendFormat": "__auto",
"range": true,
- "refId": "A"
+ "refId": "A",
+ "useBackend": false
}
],
"title": "Put Blocks Ops",
@@ -855,8 +870,7 @@
},
{
"datasource": {
- "type": "prometheus",
- "uid": "${DS_PROMETHEUS}"
+ "type": "prometheus"
},
"fieldConfig": {
"defaults": {
@@ -935,15 +949,18 @@
"targets": [
{
"datasource": {
- "type": "prometheus",
- "uid": "${DS_PROMETHEUS}"
+ "type": "prometheus"
},
- "editorMode": "code",
- "expr": "rate(storage_container_metrics_bytes_read_chunk[$__rate_interval])",
+ "disableTextWrap": false,
+ "editorMode": "builder",
+ "expr": "rate(storage_container_metrics_bytes_read_chunk[$__interval])",
+ "fullMetaSearch": false,
+ "includeNullMetadata": true,
"instant": false,
"legendFormat": "Datanode={{hostname}}",
"range": true,
- "refId": "A"
+ "refId": "A",
+ "useBackend": false
}
],
"title": "Read Chunk Traffic",
@@ -951,8 +968,7 @@
},
{
"datasource": {
- "type": "prometheus",
- "uid": "${DS_PROMETHEUS}"
+ "type": "prometheus"
},
"fieldConfig": {
"defaults": {
@@ -1031,15 +1047,18 @@
"targets": [
{
"datasource": {
- "type": "prometheus",
- "uid": "${DS_PROMETHEUS}"
+ "type": "prometheus"
},
- "editorMode": "code",
- "expr": "sum(rate(storage_container_metrics_bytes_read_chunk[$__rate_interval]))",
+ "disableTextWrap": false,
+ "editorMode": "builder",
+ "expr": "sum(rate(storage_container_metrics_bytes_read_chunk[$__interval]))",
+ "fullMetaSearch": false,
+ "includeNullMetadata": true,
"instant": false,
"legendFormat": "Datanode={{hostname}}",
"range": true,
- "refId": "A"
+ "refId": "A",
+ "useBackend": false
}
],
"title": "Total Read Chunk Traffic",
@@ -1047,8 +1066,7 @@
},
{
"datasource": {
- "type": "prometheus",
- "uid": "${DS_PROMETHEUS}"
+ "type": "prometheus"
},
"fieldConfig": {
"defaults": {
@@ -1126,15 +1144,18 @@
"targets": [
{
"datasource": {
- "type": "prometheus",
- "uid": "${DS_PROMETHEUS}"
+ "type": "prometheus"
},
+ "disableTextWrap": false,
"editorMode": "builder",
- "expr": "rate(storage_container_metrics_num_read_chunk[$__rate_interval])",
+ "expr": "rate(storage_container_metrics_num_read_chunk[$__interval])",
+ "fullMetaSearch": false,
+ "includeNullMetadata": true,
"instant": false,
"legendFormat": "Datanode={{hostname}}",
"range": true,
- "refId": "A"
+ "refId": "A",
+ "useBackend": false
}
],
"title": "Read Chunks Ops",
@@ -1148,13 +1169,13 @@
"list": []
},
"time": {
- "from": "now-3h",
+ "from": "now-7d",
"to": "now"
},
"timepicker": {},
"timezone": "browser",
"title": "Datanode Chunk Read/Write Dashboard",
"uid": "edj2lc6lfn5s0a",
- "version": 15,
+ "version": 4,
"weekStart": ""
}
\ No newline at end of file
diff --git a/hadoop-ozone/dist/src/main/compose/common/grafana/dashboards/Ozone - CreateKey Metrics.json b/hadoop-ozone/dist/src/main/compose/common/grafana/dashboards/Ozone - CreateKey Metrics.json
index 78b027afd2e..3ec057b205f 100644
--- a/hadoop-ozone/dist/src/main/compose/common/grafana/dashboards/Ozone - CreateKey Metrics.json
+++ b/hadoop-ozone/dist/src/main/compose/common/grafana/dashboards/Ozone - CreateKey Metrics.json
@@ -15,7 +15,6 @@
"editable": true,
"fiscalYearStartMonth": 0,
"graphTooltip": 0,
- "id": null,
"links": [],
"liveNow": false,
"panels": [
@@ -27,6 +26,308 @@
"x": 0,
"y": 0
},
+ "id": 65,
+ "panels": [],
+ "title": "OM Operations",
+ "type": "row"
+ },
+ {
+ "datasource": {
+ "type": "prometheus"
+ },
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "mode": "palette-classic"
+ },
+ "custom": {
+ "axisBorderShow": false,
+ "axisCenteredZero": false,
+ "axisColorMode": "text",
+ "axisLabel": "",
+ "axisPlacement": "auto",
+ "barAlignment": 0,
+ "drawStyle": "line",
+ "fillOpacity": 0,
+ "gradientMode": "none",
+ "hideFrom": {
+ "legend": false,
+ "tooltip": false,
+ "viz": false
+ },
+ "insertNulls": false,
+ "lineInterpolation": "linear",
+ "lineWidth": 1,
+ "pointSize": 5,
+ "scaleDistribution": {
+ "type": "linear"
+ },
+ "showPoints": "auto",
+ "spanNulls": false,
+ "stacking": {
+ "group": "A",
+ "mode": "none"
+ },
+ "thresholdsStyle": {
+ "mode": "off"
+ }
+ },
+ "mappings": [],
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "green",
+ "value": null
+ },
+ {
+ "color": "red",
+ "value": 80
+ }
+ ]
+ }
+ },
+ "overrides": []
+ },
+ "gridPos": {
+ "h": 8,
+ "w": 12,
+ "x": 0,
+ "y": 1
+ },
+ "id": 68,
+ "options": {
+ "legend": {
+ "calcs": [],
+ "displayMode": "list",
+ "placement": "bottom",
+ "showLegend": true
+ },
+ "tooltip": {
+ "mode": "single",
+ "sort": "none"
+ }
+ },
+ "targets": [
+ {
+ "datasource": {
+ "type": "prometheus"
+ },
+ "disableTextWrap": false,
+ "editorMode": "code",
+ "expr": "rate(om_metrics_num_key_commits[1m])",
+ "fullMetaSearch": false,
+ "includeNullMetadata": false,
+ "instant": false,
+ "legendFormat": "{{hostname}}",
+ "range": true,
+ "refId": "A",
+ "useBackend": false
+ }
+ ],
+ "title": "Rate of Key Commits",
+ "type": "timeseries"
+ },
+ {
+ "datasource": {
+ "type": "prometheus"
+ },
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "mode": "palette-classic"
+ },
+ "custom": {
+ "axisBorderShow": false,
+ "axisCenteredZero": false,
+ "axisColorMode": "text",
+ "axisLabel": "",
+ "axisPlacement": "auto",
+ "barAlignment": 0,
+ "drawStyle": "line",
+ "fillOpacity": 0,
+ "gradientMode": "none",
+ "hideFrom": {
+ "legend": false,
+ "tooltip": false,
+ "viz": false
+ },
+ "insertNulls": false,
+ "lineInterpolation": "linear",
+ "lineWidth": 1,
+ "pointSize": 5,
+ "scaleDistribution": {
+ "type": "linear"
+ },
+ "showPoints": "auto",
+ "spanNulls": false,
+ "stacking": {
+ "group": "A",
+ "mode": "none"
+ },
+ "thresholdsStyle": {
+ "mode": "off"
+ }
+ },
+ "mappings": [],
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "green",
+ "value": null
+ },
+ {
+ "color": "red",
+ "value": 80
+ }
+ ]
+ }
+ },
+ "overrides": []
+ },
+ "gridPos": {
+ "h": 8,
+ "w": 12,
+ "x": 12,
+ "y": 1
+ },
+ "id": 67,
+ "options": {
+ "legend": {
+ "calcs": [],
+ "displayMode": "list",
+ "placement": "bottom",
+ "showLegend": true
+ },
+ "tooltip": {
+ "mode": "single",
+ "sort": "none"
+ }
+ },
+ "targets": [
+ {
+ "datasource": {
+ "type": "prometheus"
+ },
+ "disableTextWrap": false,
+ "editorMode": "code",
+ "expr": "rate(om_metrics_ec_key_create_fails_total[1m])",
+ "fullMetaSearch": false,
+ "includeNullMetadata": false,
+ "instant": false,
+ "legendFormat": "{{hostname}}",
+ "range": true,
+ "refId": "A",
+ "useBackend": false
+ }
+ ],
+ "title": "Rate of Key Commit Failures",
+ "type": "timeseries"
+ },
+ {
+ "datasource": {
+ "type": "prometheus"
+ },
+ "description": "Rate at which data is committed across objects in OM. ",
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "mode": "palette-classic"
+ },
+ "custom": {
+ "axisBorderShow": false,
+ "axisCenteredZero": false,
+ "axisColorMode": "text",
+ "axisLabel": "",
+ "axisPlacement": "auto",
+ "barAlignment": 0,
+ "drawStyle": "line",
+ "fillOpacity": 0,
+ "gradientMode": "none",
+ "hideFrom": {
+ "legend": false,
+ "tooltip": false,
+ "viz": false
+ },
+ "insertNulls": false,
+ "lineInterpolation": "linear",
+ "lineWidth": 1,
+ "pointSize": 5,
+ "scaleDistribution": {
+ "type": "linear"
+ },
+ "showPoints": "auto",
+ "spanNulls": false,
+ "stacking": {
+ "group": "A",
+ "mode": "none"
+ },
+ "thresholdsStyle": {
+ "mode": "off"
+ }
+ },
+ "mappings": [],
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "green",
+ "value": null
+ },
+ {
+ "color": "red",
+ "value": 80
+ }
+ ]
+ },
+ "unit": "bytes"
+ },
+ "overrides": []
+ },
+ "gridPos": {
+ "h": 8,
+ "w": 12,
+ "x": 0,
+ "y": 9
+ },
+ "id": 66,
+ "options": {
+ "legend": {
+ "calcs": [],
+ "displayMode": "list",
+ "placement": "bottom",
+ "showLegend": true
+ },
+ "tooltip": {
+ "mode": "single",
+ "sort": "none"
+ }
+ },
+ "targets": [
+ {
+ "datasource": {
+ "type": "prometheus"
+ },
+ "editorMode": "code",
+ "expr": "rate(om_metrics_total_data_committed[60s])",
+ "instant": false,
+ "legendFormat": "{{hostname}}",
+ "range": true,
+ "refId": "A"
+ }
+ ],
+ "title": "Aggregate Rate of Data Commit",
+ "type": "timeseries"
+ },
+ {
+ "collapsed": true,
+ "gridPos": {
+ "h": 1,
+ "w": 24,
+ "x": 0,
+ "y": 17
+ },
"id": 52,
"panels": [
{
@@ -75,8 +376,7 @@
"mode": "absolute",
"steps": [
{
- "color": "green",
- "value": null
+ "color": "green"
},
{
"color": "red",
@@ -117,7 +417,7 @@
"h": 7,
"w": 8,
"x": 0,
- "y": 1
+ "y": 25
},
"id": 11,
"options": {
@@ -199,8 +499,7 @@
"mode": "absolute",
"steps": [
{
- "color": "green",
- "value": null
+ "color": "green"
},
{
"color": "red",
@@ -215,7 +514,7 @@
"h": 7,
"w": 8,
"x": 8,
- "y": 1
+ "y": 25
},
"id": 12,
"options": {
@@ -261,7 +560,7 @@
"h": 1,
"w": 24,
"x": 0,
- "y": 1
+ "y": 18
},
"id": 51,
"panels": [
@@ -275,6 +574,7 @@
"mode": "palette-classic"
},
"custom": {
+ "axisBorderShow": false,
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "no. of keys",
@@ -325,7 +625,7 @@
"h": 7,
"w": 8,
"x": 0,
- "y": 2
+ "y": 26
},
"id": 13,
"options": {
@@ -386,7 +686,7 @@
"h": 1,
"w": 24,
"x": 0,
- "y": 2
+ "y": 19
},
"id": 50,
"panels": [
@@ -400,6 +700,7 @@
"mode": "palette-classic"
},
"custom": {
+ "axisBorderShow": false,
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "time (ns)",
@@ -476,7 +777,7 @@
"h": 8,
"w": 8,
"x": 0,
- "y": 3
+ "y": 27
},
"id": 15,
"options": {
@@ -531,6 +832,7 @@
"mode": "palette-classic"
},
"custom": {
+ "axisBorderShow": false,
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "no. of ops",
@@ -581,7 +883,7 @@
"h": 8,
"w": 8,
"x": 8,
- "y": 3
+ "y": 27
},
"id": 14,
"options": {
@@ -658,7 +960,7 @@
"h": 1,
"w": 24,
"x": 0,
- "y": 3
+ "y": 20
},
"id": 8,
"panels": [
@@ -673,6 +975,7 @@
"mode": "palette-classic"
},
"custom": {
+ "axisBorderShow": false,
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "",
@@ -748,7 +1051,7 @@
"h": 8,
"w": 8,
"x": 0,
- "y": 4
+ "y": 28
},
"id": 16,
"options": {
@@ -793,6 +1096,7 @@
"mode": "palette-classic"
},
"custom": {
+ "axisBorderShow": false,
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "",
@@ -843,7 +1147,7 @@
"h": 8,
"w": 8,
"x": 8,
- "y": 4
+ "y": 28
},
"id": 17,
"options": {
@@ -904,7 +1208,7 @@
"h": 1,
"w": 24,
"x": 0,
- "y": 4
+ "y": 21
},
"id": 64,
"panels": [
@@ -918,6 +1222,7 @@
"mode": "palette-classic"
},
"custom": {
+ "axisBorderShow": false,
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "no. of ops",
@@ -993,7 +1298,7 @@
"h": 8,
"w": 8,
"x": 0,
- "y": 13
+ "y": 29
},
"id": 10,
"options": {
@@ -1054,7 +1359,7 @@
"h": 1,
"w": 24,
"x": 0,
- "y": 5
+ "y": 22
},
"id": 63,
"panels": [
@@ -1068,6 +1373,7 @@
"mode": "palette-classic"
},
"custom": {
+ "axisBorderShow": false,
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "no. of keys",
@@ -1143,7 +1449,7 @@
"h": 8,
"w": 8,
"x": 0,
- "y": 1
+ "y": 30
},
"id": 49,
"options": {
@@ -1189,7 +1495,7 @@
"h": 1,
"w": 24,
"x": 0,
- "y": 6
+ "y": 23
},
"id": 53,
"panels": [
@@ -1253,7 +1559,7 @@
"h": 7,
"w": 8,
"x": 0,
- "y": 20
+ "y": 44
},
"id": 9,
"options": {
@@ -1410,7 +1716,7 @@
"h": 1,
"w": 24,
"x": 0,
- "y": 7
+ "y": 24
},
"id": 54,
"panels": [
@@ -1424,6 +1730,7 @@
"mode": "palette-classic"
},
"custom": {
+ "axisBorderShow": false,
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "",
@@ -1474,7 +1781,7 @@
"h": 8,
"w": 8,
"x": 0,
- "y": 21
+ "y": 32
},
"id": 48,
"options": {
@@ -1583,6 +1890,7 @@
"mode": "palette-classic"
},
"custom": {
+ "axisBorderShow": false,
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "",
@@ -1658,7 +1966,7 @@
"h": 8,
"w": 8,
"x": 8,
- "y": 21
+ "y": 32
},
"id": 24,
"options": {
@@ -1719,6 +2027,7 @@
"mode": "palette-classic"
},
"custom": {
+ "axisBorderShow": false,
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "Time (ns)",
@@ -1770,7 +2079,7 @@
"h": 8,
"w": 8,
"x": 16,
- "y": 21
+ "y": 32
},
"id": 45,
"options": {
@@ -1879,7 +2188,7 @@
"h": 1,
"w": 24,
"x": 0,
- "y": 8
+ "y": 25
},
"id": 56,
"panels": [
@@ -1943,7 +2252,7 @@
"h": 8,
"w": 8,
"x": 0,
- "y": 9
+ "y": 33
},
"id": 29,
"options": {
@@ -2038,7 +2347,7 @@
"h": 8,
"w": 8,
"x": 8,
- "y": 9
+ "y": 33
},
"id": 30,
"options": {
@@ -2083,7 +2392,7 @@
"h": 1,
"w": 24,
"x": 0,
- "y": 9
+ "y": 26
},
"id": 7,
"panels": [
@@ -2147,7 +2456,7 @@
"h": 8,
"w": 8,
"x": 0,
- "y": 8
+ "y": 32
},
"id": 26,
"options": {
@@ -2259,7 +2568,7 @@
"h": 8,
"w": 8,
"x": 8,
- "y": 8
+ "y": 32
},
"id": 25,
"options": {
@@ -2320,7 +2629,7 @@
"h": 1,
"w": 24,
"x": 0,
- "y": 10
+ "y": 27
},
"id": 57,
"panels": [
@@ -2384,7 +2693,7 @@
"h": 7,
"w": 8,
"x": 0,
- "y": 9
+ "y": 33
},
"id": 34,
"options": {
@@ -2495,7 +2804,7 @@
"h": 7,
"w": 8,
"x": 8,
- "y": 9
+ "y": 33
},
"id": 32,
"options": {
@@ -2572,7 +2881,7 @@
"h": 1,
"w": 24,
"x": 0,
- "y": 12
+ "y": 28
},
"id": 59,
"panels": [
@@ -2636,7 +2945,7 @@
"h": 7,
"w": 8,
"x": 0,
- "y": 11
+ "y": 35
},
"id": 37,
"options": {
@@ -2731,7 +3040,7 @@
"h": 7,
"w": 8,
"x": 8,
- "y": 11
+ "y": 35
},
"id": 36,
"options": {
@@ -2776,7 +3085,7 @@
"h": 1,
"w": 24,
"x": 0,
- "y": 13
+ "y": 29
},
"id": 60,
"panels": [
@@ -2840,7 +3149,7 @@
"h": 8,
"w": 8,
"x": 0,
- "y": 12
+ "y": 36
},
"id": 33,
"options": {
@@ -2885,7 +3194,7 @@
"h": 1,
"w": 24,
"x": 0,
- "y": 14
+ "y": 30
},
"id": 40,
"panels": [
@@ -2899,6 +3208,7 @@
"mode": "palette-classic"
},
"custom": {
+ "axisBorderShow": false,
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "no. of ops",
@@ -2949,7 +3259,7 @@
"h": 7,
"w": 8,
"x": 0,
- "y": 13
+ "y": 38
},
"id": 44,
"options": {
@@ -3026,7 +3336,7 @@
"h": 1,
"w": 24,
"x": 0,
- "y": 15
+ "y": 31
},
"id": 61,
"panels": [
@@ -3040,6 +3350,7 @@
"mode": "palette-classic"
},
"custom": {
+ "axisBorderShow": false,
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "time (ns)",
@@ -3091,7 +3402,7 @@
"h": 8,
"w": 8,
"x": 0,
- "y": 14
+ "y": 39
},
"id": 41,
"options": {
@@ -3152,6 +3463,7 @@
"mode": "palette-classic"
},
"custom": {
+ "axisBorderShow": false,
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "no. of ops",
@@ -3202,7 +3514,7 @@
"h": 8,
"w": 12,
"x": 8,
- "y": 14
+ "y": 39
},
"id": 42,
"options": {
@@ -3247,7 +3559,7 @@
"h": 1,
"w": 24,
"x": 0,
- "y": 16
+ "y": 32
},
"id": 62,
"panels": [
@@ -3261,6 +3573,7 @@
"mode": "palette-classic"
},
"custom": {
+ "axisBorderShow": false,
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "Time (ns)",
@@ -3312,7 +3625,7 @@
"h": 9,
"w": 8,
"x": 0,
- "y": 15
+ "y": 40
},
"id": 46,
"options": {
@@ -3421,6 +3734,7 @@
"mode": "palette-classic"
},
"custom": {
+ "axisBorderShow": false,
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "",
@@ -3496,7 +3810,7 @@
"h": 9,
"w": 8,
"x": 8,
- "y": 15
+ "y": 40
},
"id": 47,
"options": {
@@ -3557,6 +3871,7 @@
"mode": "palette-classic"
},
"custom": {
+ "axisBorderShow": false,
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "",
@@ -3607,7 +3922,7 @@
"h": 9,
"w": 8,
"x": 16,
- "y": 15
+ "y": 40
},
"id": 22,
"options": {
@@ -3718,13 +4033,12 @@
"list": []
},
"time": {
- "from": "now-12h",
+ "from": "now-15m",
"to": "now"
},
"timeRangeUpdatedDuringEditOrView": false,
"timepicker": {},
"timezone": "",
"title": "Create key Dashboard",
- "version": 36,
"weekStart": ""
}
\ No newline at end of file
diff --git a/hadoop-ozone/dist/src/main/compose/testlib.sh b/hadoop-ozone/dist/src/main/compose/testlib.sh
index 44b4f303807..1e9cc85781a 100755
--- a/hadoop-ozone/dist/src/main/compose/testlib.sh
+++ b/hadoop-ozone/dist/src/main/compose/testlib.sh
@@ -37,8 +37,6 @@ create_results_dir() {
#delete previous results
[[ "${OZONE_KEEP_RESULTS:-}" == "true" ]] || rm -rf "$RESULT_DIR"
mkdir -p "$RESULT_DIR"
- #Should be writeable from the docker containers where user is different.
- chmod ogu+w "$RESULT_DIR"
}
## @description find all the test*.sh scripts in the immediate child dirs
@@ -390,22 +388,44 @@ cleanup_docker_images() {
fi
}
+## @description Run Robot Framework report generator (rebot) in ozone-runner container.
+## @param input directory where source Robot XML files are
+## @param output directory where report should be placed
+## @param rebot options and arguments
+run_rebot() {
+ local input_dir="$(realpath "$1")"
+ local output_dir="$(realpath "$2")"
+
+ shift 2
+
+ local tempdir="$(mktemp -d --suffix rebot -p "${output_dir}")"
+ #Should be writeable from the docker containers where user is different.
+ chmod a+wx "${tempdir}"
+ if docker run --rm -v "${input_dir}":/rebot-input -v "${tempdir}":/rebot-output -w /rebot-input \
+ $(get_runner_image_spec) \
+ bash -c "rebot --nostatusrc -d /rebot-output $@"; then
+ mv -v "${tempdir}"/* "${output_dir}"/
+ fi
+ rmdir "${tempdir}"
+}
+
## @description Generate robot framework reports based on the saved results.
generate_report(){
local title="${1:-${COMPOSE_ENV_NAME}}"
local dir="${2:-${RESULT_DIR}}"
local xunitdir="${3:-}"
- if command -v rebot > /dev/null 2>&1; then
- #Generate the combined output and return with the right exit code (note: robot = execute test, rebot = generate output)
- if [ -z "${xunitdir}" ]; then
- rebot --reporttitle "${title}" -N "${title}" -d "${dir}" "${dir}/*.xml"
- else
- rebot --reporttitle "${title}" -N "${title}" --xunit ${xunitdir}/TEST-ozone.xml -d "${dir}" "${dir}/*.xml"
- fi
- else
- echo "Robot framework is not installed, the reports cannot be generated (sudo pip install robotframework)."
- exit 1
+ if [[ -n "$(find "${dir}" -mindepth 1 -maxdepth 1 -name "*.xml")" ]]; then
+ xunit_args=""
+ if [[ -n "${xunitdir}" ]] && [[ -e "${xunitdir}" ]]; then
+ xunit_args="--xunit TEST-ozone.xml"
+ fi
+
+ run_rebot "$dir" "$dir" "--reporttitle '${title}' -N '${title}' ${xunit_args} *.xml"
+
+ if [[ -n "${xunit_args}" ]]; then
+ mv -v "${dir}"/TEST-ozone.xml "${xunitdir}"/ || rm -f "${dir}"/TEST-ozone.xml
+ fi
fi
}
@@ -429,8 +449,8 @@ copy_results() {
target_dir="${target_dir}/${test_script_name}"
fi
- if command -v rebot > /dev/null 2>&1 && [[ -n "$(find "${result_dir}" -name "*.xml")" ]]; then
- rebot --nostatusrc -N "${test_name}" -l NONE -r NONE -o "${all_result_dir}/${test_name}.xml" "${result_dir}"/*.xml \
+ if [[ -n "$(find "${result_dir}" -mindepth 1 -maxdepth 1 -name "*.xml")" ]]; then
+ run_rebot "${result_dir}" "${all_result_dir}" "-N '${test_name}' -l NONE -r NONE -o '${test_name}.xml' *.xml" \
&& rm -fv "${result_dir}"/*.xml "${result_dir}"/log.html "${result_dir}"/report.html
fi
@@ -505,14 +525,21 @@ prepare_for_binary_image() {
## @description Define variables required for using `ozone-runner` docker image
## (no binaries included)
## @param `ozone-runner` image version (optional)
-prepare_for_runner_image() {
+get_runner_image_spec() {
local default_version=${docker.ozone-runner.version} # set at build-time from Maven property
local runner_version=${OZONE_RUNNER_VERSION:-${default_version}} # may be specified by user running the test
local runner_image=${OZONE_RUNNER_IMAGE:-apache/ozone-runner} # may be specified by user running the test
local v=${1:-${runner_version}} # prefer explicit argument
+ echo "${runner_image}:${v}"
+}
+
+## @description Define variables required for using `ozone-runner` docker image
+## (no binaries included)
+## @param `ozone-runner` image version (optional)
+prepare_for_runner_image() {
export OZONE_DIR=/opt/hadoop
- export OZONE_IMAGE="${runner_image}:${v}"
+ export OZONE_IMAGE="$(get_runner_image_spec "$@")"
}
## @description Executing the Ozone Debug CLI related robot tests
diff --git a/hadoop-ozone/dist/src/main/compose/upgrade/test.sh b/hadoop-ozone/dist/src/main/compose/upgrade/test.sh
index 9d7ec5d4e60..6fc4763631b 100755
--- a/hadoop-ozone/dist/src/main/compose/upgrade/test.sh
+++ b/hadoop-ozone/dist/src/main/compose/upgrade/test.sh
@@ -35,7 +35,7 @@ RESULT_DIR="$ALL_RESULT_DIR" create_results_dir
# This is the version of Ozone that should use the runner image to run the
# code that was built. Other versions will pull images from docker hub.
-export OZONE_CURRENT_VERSION=1.5.0
+export OZONE_CURRENT_VERSION="${ozone.version}"
run_test ha non-rolling-upgrade 1.4.0 "$OZONE_CURRENT_VERSION"
# run_test ha non-rolling-upgrade 1.3.0 "$OZONE_CURRENT_VERSION"
# run_test ha non-rolling-upgrade 1.2.1 "$OZONE_CURRENT_VERSION"
diff --git a/hadoop-ozone/dist/src/main/compose/xcompat/test.sh b/hadoop-ozone/dist/src/main/compose/xcompat/test.sh
index 419d397c19e..695d8bf06ab 100755
--- a/hadoop-ozone/dist/src/main/compose/xcompat/test.sh
+++ b/hadoop-ozone/dist/src/main/compose/xcompat/test.sh
@@ -21,7 +21,7 @@ COMPOSE_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
export COMPOSE_DIR
basename=$(basename ${COMPOSE_DIR})
-current_version=1.5.0
+current_version="${ozone.version}"
old_versions="1.0.0 1.1.0 1.2.1 1.3.0 1.4.0" # container is needed for each version in clients.yaml
# shellcheck source=hadoop-ozone/dist/src/main/compose/testlib.sh
@@ -77,7 +77,8 @@ test_cross_compatibility() {
test_ec_cross_compatibility() {
echo "Running Erasure Coded storage backward compatibility tests."
- local cluster_versions_with_ec="1.3.0 1.4.0"
+ # local cluster_versions_with_ec="1.3.0 1.4.0 ${current_version}"
+ local cluster_versions_with_ec="${current_version}" # until HDDS-11334
local non_ec_client_versions="1.0.0 1.1.0 1.2.1"
for cluster_version in ${cluster_versions_with_ec}; do
diff --git a/hadoop-ozone/dist/src/main/smoketest/basic/ozone-shell-lib.robot b/hadoop-ozone/dist/src/main/smoketest/basic/ozone-shell-lib.robot
index 83f0a1b69e2..719cdaf83f3 100644
--- a/hadoop-ozone/dist/src/main/smoketest/basic/ozone-shell-lib.robot
+++ b/hadoop-ozone/dist/src/main/smoketest/basic/ozone-shell-lib.robot
@@ -92,18 +92,43 @@ Test ozone shell
Test ozone shell errors
[arguments] ${protocol} ${server} ${volume}
- ${result} = Execute and checkrc ozone sh volume create ${protocol}${server}/${volume} --space-quota invalid 255
- Should contain ${result} invalid
+ ${result} = Execute and checkrc ozone sh volume create ${protocol}${server}/${volume} --space-quota 1.5GB 255
+ Should contain ${result} 1.5GB is invalid
+ ${result} = Execute and checkrc ozone sh volume create ${protocol}${server}/${volume} --namespace-quota 1.5 255
+ Should contain ${result} 1.5 is invalid
Execute and checkrc ozone sh volume create ${protocol}${server}/${volume} 0
${result} = Execute and checkrc ozone sh bucket create ${protocol}${server}/${volume}/bucket_1 255
Should contain ${result} INVALID_BUCKET_NAME
+ ${result} = Execute and checkrc ozone sh bucket create ${protocol}${server}/${volume}/bucket1 --space-quota 1.5GB 255
+ Should contain ${result} 1.5GB is invalid
+ ${result} = Execute and checkrc ozone sh bucket create ${protocol}${server}/${volume}/bucket1 --namespace-quota 1.5 255
+ Should contain ${result} 1.5 is invalid
${result} = Execute and checkrc ozone sh bucket create ${protocol}${server}/${volume}/bucket1 --layout Invalid 2
Should contain ${result} Usage
Execute and checkrc ozone sh bucket create ${protocol}${server}/${volume}/bucket1 0
${result} = Execute and checkrc ozone sh key info ${protocol}${server}/${volume}/bucket1/non-existing 255
Should contain ${result} KEY_NOT_FOUND
${result} = Execute and checkrc ozone sh key put ${protocol}${server}/${volume}/bucket1/key1 unexisting --type invalid 2
+ ${result} = Execute and checkrc ozone sh bucket setquota ${volume}/bucket1 --space-quota 1.5 255
+ Should contain ${result} 1.5 is invalid
+ ${result} = Execute and checkrc ozone sh bucket setquota ${volume}/bucket1 --namespace-quota 1.5 255
+ Should contain ${result} 1.5 is invalid
+ ${result} = Execute and checkrc ozone sh volume setquota ${volume} --space-quota 1.5 255
+ Should contain ${result} 1.5 is invalid
+ ${result} = Execute and checkrc ozone sh volume setquota ${volume} --namespace-quota 1.5 255
+ Should contain ${result} 1.5 is invalid
+ Execute and checkrc ozone sh bucket setquota ${volume}/bucket1 --space-quota 2KB 0
+ ${result} = Execute and checkrc ozone sh key put ${volume}/bucket1/key1 /opt/hadoop/NOTICE.txt 255
+ Should contain ${result} QUOTA_EXCEEDED
+ ${result} = Execute and checkrc ozone sh volume setquota ${volume} --space-quota 1KB 255
+ Should contain ${result} QUOTA_EXCEEDED
+ Execute and checkrc ozone sh bucket clrquota ${volume}/bucket1 --space-quota 0
+ ${result} = Execute and checkrc ozone sh volume setquota ${volume} --space-quota 1GB 255
+ Should contain ${result} QUOTA_ERROR
Execute and checkrc ozone sh bucket delete ${protocol}${server}/${volume}/bucket1 0
+ Execute and checkrc ozone sh volume setquota ${volume} --space-quota 1GB 0
+ ${result} = Execute and checkrc ozone sh bucket create ${protocol}${server}/${volume}/bucket1 255
+ Should contain ${result} QUOTA_ERROR
Execute and checkrc ozone sh volume delete ${protocol}${server}/${volume} 0
diff --git a/hadoop-ozone/dist/src/shell/conf/om-audit-log4j2.properties b/hadoop-ozone/dist/src/shell/conf/om-audit-log4j2.properties
index b9b11bb6289..40d02bae2c3 100644
--- a/hadoop-ozone/dist/src/shell/conf/om-audit-log4j2.properties
+++ b/hadoop-ozone/dist/src/shell/conf/om-audit-log4j2.properties
@@ -60,7 +60,7 @@ filter.write.onMismatch=NEUTRAL
#appender.console.layout.pattern=%d{DEFAULT} | %-5level | %c{1} | %msg | %throwable{3} %n
# Comment this line when using both console and rolling appenders
-appenders=rolling
+appenders=rolling,sysrolling
# Rolling File Appender with size & time thresholds.
# Rolling is triggered when either threshold is breached.
@@ -88,13 +88,39 @@ appender.rolling.strategy.delete.ifFileName.glob=om-audit-*.log.gz
appender.rolling.strategy.delete.ifLastModified.type=IfLastModified
appender.rolling.strategy.delete.ifLastModified.age=30d
-loggers=audit
+appender.sysrolling.type=RollingFile
+appender.sysrolling.name=SysRollingFile
+appender.sysrolling.fileName =${sys:hadoop.log.dir}/om-sys-audit-${hostName}.log
+appender.sysrolling.filePattern=${sys:hadoop.log.dir}/om-sys-audit-${hostName}-%d{yyyy-MM-dd-HH-mm-ss}-%i.log.gz
+appender.sysrolling.layout.type=PatternLayout
+appender.sysrolling.layout.pattern=%d{DEFAULT} | %-5level | %c{1} | %msg | %throwable{3} %n
+appender.sysrolling.policies.type=Policies
+appender.sysrolling.policies.time.type=TimeBasedTriggeringPolicy
+appender.sysrolling.policies.time.interval=86400
+appender.sysrolling.policies.size.type=SizeBasedTriggeringPolicy
+appender.sysrolling.policies.size.size=64MB
+appender.sysrolling.strategy.type=DefaultRolloverStrategy
+appender.sysrolling.strategy.delete.type=Delete
+appender.sysrolling.strategy.delete.basePath=${sys:hadoop.log.dir}
+appender.sysrolling.strategy.delete.maxDepth=1
+appender.sysrolling.strategy.delete.ifFileName.type=IfFileName
+appender.sysrolling.strategy.delete.ifFileName.glob=om-sys-audit-*.log.gz
+appender.sysrolling.strategy.delete.ifLastModified.type=IfLastModified
+appender.sysrolling.strategy.delete.ifLastModified.age=30d
+
+loggers=audit,sysaudit
logger.audit.type=AsyncLogger
logger.audit.name=OMAudit
logger.audit.level=INFO
logger.audit.appenderRefs=rolling
logger.audit.appenderRef.file.ref=RollingFile
+logger.sysaudit.type=AsyncLogger
+logger.sysaudit.name=OMSystemAudit
+logger.sysaudit.level=INFO
+logger.sysaudit.appenderRefs=sysrolling
+logger.sysaudit.appenderRef.file.ref=SysRollingFile
+
rootLogger.level=INFO
#rootLogger.appenderRefs=stdout
#rootLogger.appenderRef.stdout.ref=STDOUT
diff --git a/hadoop-ozone/dist/src/shell/ozone/ozone b/hadoop-ozone/dist/src/shell/ozone/ozone
index 99fce8c2d44..22ceed9ed3c 100755
--- a/hadoop-ozone/dist/src/shell/ozone/ozone
+++ b/hadoop-ozone/dist/src/shell/ozone/ozone
@@ -250,6 +250,7 @@ function ozone_suppress_shell_log
&& [[ -z "${OZONE_ORIGINAL_ROOT_LOGGER}" ]]; then
OZONE_LOGLEVEL=OFF
OZONE_ROOT_LOGGER="${OZONE_LOGLEVEL},console"
+ OZONE_OPTS="${OZONE_OPTS} -Dslf4j.internal.verbosity=ERROR"
fi
}
diff --git a/hadoop-ozone/httpfsgateway/pom.xml b/hadoop-ozone/httpfsgateway/pom.xml
index 5be2a4be83f..7664643b153 100644
--- a/hadoop-ozone/httpfsgateway/pom.xml
+++ b/hadoop-ozone/httpfsgateway/pom.xml
@@ -40,6 +40,14 @@
+
+ org.apache.ozone
+ hdds-common
+
+
+ org.apache.ozone
+ hdds-config
+
org.apache.ozone
hdds-server-framework
@@ -86,6 +94,10 @@
commons-codec
runtime
+
+ org.apache.commons
+ commons-lang3
+
ch.qos.reload4j
reload4j
@@ -138,6 +150,18 @@
+
+ com.fasterxml.jackson.core
+ jackson-databind
+
+
+ com.google.guava
+ guava
+
+
+ jakarta.ws.rs
+ jakarta.ws.rs-api
+
jakarta.xml.bind
jakarta.xml.bind-api
@@ -146,6 +170,10 @@
org.glassfish.hk2
hk2-api
+
+ org.glassfish.jersey.core
+ jersey-server
+
org.glassfish.jersey.inject
jersey-hk2
diff --git a/hadoop-ozone/insight/pom.xml b/hadoop-ozone/insight/pom.xml
index ae0bc5cd3aa..bcfb1660244 100644
--- a/hadoop-ozone/insight/pom.xml
+++ b/hadoop-ozone/insight/pom.xml
@@ -31,6 +31,26 @@ https://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+ org.apache.ozone
+ hdds-common
+
+
+ org.apache.ozone
+ hdds-config
+
+
+ org.apache.ozone
+ hdds-container-service
+
+
+ org.apache.ozone
+ hdds-interface-admin
+
+
+ org.apache.ozone
+ hdds-interface-client
+
org.apache.ozone
ozone-manager
@@ -51,6 +71,10 @@ https://maven.apache.org/xsd/maven-4.0.0.xsd">
org.apache.ozone
ozone-filesystem
+
+ org.apache.ozone
+ ozone-interface-client
+
org.apache.ozone
hdds-server-framework
@@ -59,6 +83,18 @@ https://maven.apache.org/xsd/maven-4.0.0.xsd">
org.apache.ozone
hdds-tools
+
+ org.apache.httpcomponents
+ httpclient
+
+
+ org.apache.httpcomponents
+ httpcore
+
+
+ info.picocli
+ picocli
+
jakarta.xml.bind
jakarta.xml.bind-api
diff --git a/hadoop-ozone/integration-test/pom.xml b/hadoop-ozone/integration-test/pom.xml
index e1ba4af83db..f66f64d2874 100644
--- a/hadoop-ozone/integration-test/pom.xml
+++ b/hadoop-ozone/integration-test/pom.xml
@@ -238,6 +238,11 @@ https://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+ org.apache.ratis
+ ratis-server
+
+
org.hamcrest
hamcrest
diff --git a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/fs/ozone/TestHSync.java b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/fs/ozone/TestHSync.java
index 466490290b7..49b515d53c5 100644
--- a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/fs/ozone/TestHSync.java
+++ b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/fs/ozone/TestHSync.java
@@ -32,6 +32,7 @@
import java.util.UUID;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Stream;
@@ -44,6 +45,9 @@
import org.apache.hadoop.fs.FSDataInputStream;
import org.apache.hadoop.fs.FileAlreadyExistsException;
import org.apache.hadoop.hdds.conf.StorageUnit;
+import org.apache.hadoop.hdds.scm.ErrorInjector;
+import org.apache.hadoop.hdds.scm.XceiverClientManager;
+import org.apache.hadoop.hdds.scm.pipeline.Pipeline;
import org.apache.hadoop.hdds.scm.storage.BlockOutputStream;
import org.apache.hadoop.hdds.scm.storage.BufferPool;
import org.apache.hadoop.hdds.utils.IOUtils;
@@ -90,13 +94,15 @@
import org.apache.hadoop.ozone.om.helpers.OmKeyInfo;
import org.apache.hadoop.ozone.om.helpers.RepeatedOmKeyInfo;
-import org.apache.hadoop.ozone.om.protocol.OzoneManagerProtocol;
import org.apache.hadoop.ozone.om.service.OpenKeyCleanupService;
-import org.apache.hadoop.ozone.om.upgrade.OMLayoutFeature;
-import org.apache.hadoop.ozone.upgrade.UpgradeFinalizer;
import org.apache.hadoop.security.UserGroupInformation;
import org.apache.hadoop.util.Time;
import org.apache.ozone.test.GenericTestUtils;
+import org.apache.ratis.protocol.ClientId;
+import org.apache.ratis.protocol.Message;
+import org.apache.ratis.protocol.RaftClientReply;
+import org.apache.ratis.protocol.RaftGroupId;
+import org.apache.ratis.protocol.RaftPeerId;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.MethodOrderer.OrderAnnotation;
@@ -121,8 +127,6 @@
import static org.apache.hadoop.ozone.OzoneConsts.OZONE_URI_SCHEME;
import static org.apache.hadoop.ozone.TestDataUtil.cleanupDeletedTable;
import static org.apache.hadoop.ozone.TestDataUtil.cleanupOpenKeyTable;
-import static org.apache.hadoop.ozone.admin.scm.FinalizeUpgradeCommandUtil.isDone;
-import static org.apache.hadoop.ozone.admin.scm.FinalizeUpgradeCommandUtil.isStarting;
import static org.apache.hadoop.ozone.om.OMConfigKeys.OZONE_DEFAULT_BUCKET_LAYOUT;
import static org.apache.hadoop.ozone.om.OMConfigKeys.OZONE_OM_ADDRESS_KEY;
import static org.apache.hadoop.ozone.om.OMConfigKeys.OZONE_OM_RATIS_ENABLE_KEY;
@@ -130,9 +134,6 @@
import static org.apache.hadoop.ozone.om.OMConfigKeys.OZONE_OM_OPEN_KEY_CLEANUP_SERVICE_INTERVAL;
import static org.apache.hadoop.ozone.om.OMConfigKeys.OZONE_OM_OPEN_KEY_EXPIRE_THRESHOLD;
import static org.apache.hadoop.ozone.om.OMConfigKeys.OZONE_OM_LEASE_HARD_LIMIT;
-import static org.apache.hadoop.ozone.om.OmUpgradeConfig.ConfigStrings.OZONE_OM_INIT_DEFAULT_LAYOUT_VERSION;
-import static org.apache.hadoop.ozone.om.exceptions.OMException.ResultCodes.NOT_SUPPORTED_OPERATION_PRIOR_FINALIZATION;
-import static org.apache.ozone.test.LambdaTestUtils.await;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
@@ -170,9 +171,6 @@ public class TestHSync {
private static OpenKeyCleanupService openKeyCleanupService;
- private static final int POLL_INTERVAL_MILLIS = 500;
- private static final int POLL_MAX_WAIT_MILLIS = 120_000;
-
@BeforeAll
public static void init() throws Exception {
final BucketLayout layout = BUCKET_LAYOUT;
@@ -186,6 +184,8 @@ public static void init() throws Exception {
CONF.setTimeDuration(OZONE_DIR_DELETING_SERVICE_INTERVAL, 100, TimeUnit.MILLISECONDS);
CONF.setBoolean("ozone.client.incremental.chunk.list", true);
CONF.setBoolean("ozone.client.stream.putblock.piggybacking", true);
+ // Unlimited key write concurrency
+ CONF.setInt("ozone.client.key.write.concurrency", -1);
CONF.setTimeDuration(OZONE_OM_OPEN_KEY_CLEANUP_SERVICE_INTERVAL,
SERVICE_INTERVAL, TimeUnit.MILLISECONDS);
CONF.setTimeDuration(OZONE_OM_OPEN_KEY_EXPIRE_THRESHOLD,
@@ -193,7 +193,6 @@ public static void init() throws Exception {
CONF.setTimeDuration(OZONE_OM_LEASE_HARD_LIMIT,
EXPIRE_THRESHOLD_MS, TimeUnit.MILLISECONDS);
CONF.set(OzoneConfigKeys.OZONE_OM_LEASE_SOFT_LIMIT, "0s");
- CONF.setInt(OZONE_OM_INIT_DEFAULT_LAYOUT_VERSION, OMLayoutFeature.QUOTA.layoutVersion());
ClientConfigForTesting.newBuilder(StorageUnit.BYTES)
.setBlockSize(BLOCK_SIZE)
@@ -226,9 +225,6 @@ public static void init() throws Exception {
openKeyCleanupService =
(OpenKeyCleanupService) cluster.getOzoneManager().getKeyManager().getOpenKeyCleanupService();
openKeyCleanupService.suspend();
-
- preFinalizationChecks();
- finalizeOMUpgrade();
}
@AfterAll
@@ -239,72 +235,6 @@ public static void teardown() {
}
}
- private static void preFinalizationChecks() throws IOException {
- final String rootPath = String.format("%s://%s/",
- OZONE_OFS_URI_SCHEME, CONF.get(OZONE_OM_ADDRESS_KEY));
- CONF.set(CommonConfigurationKeysPublic.FS_DEFAULT_NAME_KEY, rootPath);
-
- final String dir = OZONE_ROOT + bucket.getVolumeName()
- + OZONE_URI_DELIMITER + bucket.getName();
-
- final Path file = new Path(dir, "pre-finalization");
- try (RootedOzoneFileSystem fs = (RootedOzoneFileSystem)FileSystem.get(CONF)) {
- try (FSDataOutputStream outputStream = fs.create(file, true)) {
- OMException omException = assertThrows(OMException.class, outputStream::hsync);
- assertFinalizationExceptionForHsyncLeaseRecovery(omException);
- }
- final OzoneManagerProtocol omClient = client.getObjectStore()
- .getClientProxy().getOzoneManagerClient();
- OMException omException = assertThrows(OMException.class,
- () -> omClient.listOpenFiles("", 100, ""));
- assertFinalizationException(omException);
-
- omException = assertThrows(OMException.class,
- () -> fs.recoverLease(file));
- assertFinalizationException(omException);
-
- fs.delete(file, false);
- }
- }
-
- private static void assertFinalizationExceptionForHsyncLeaseRecovery(OMException omException) {
- assertEquals(NOT_SUPPORTED_OPERATION_PRIOR_FINALIZATION,
- omException.getResult());
- assertThat(omException.getMessage())
- .contains("Cluster does not have the HBase support feature finalized yet");
- }
-
- private static void assertFinalizationException(OMException omException) {
- assertEquals(NOT_SUPPORTED_OPERATION_PRIOR_FINALIZATION,
- omException.getResult());
- assertThat(omException.getMessage())
- .contains("cannot be invoked before finalization.");
- }
-
- /**
- * Trigger OM upgrade finalization from the client and block until completion
- * (status FINALIZATION_DONE).
- */
- private static void finalizeOMUpgrade() throws Exception {
- // Trigger OM upgrade finalization. Ref: FinalizeUpgradeSubCommand#call
- final OzoneManagerProtocol omClient = client.getObjectStore()
- .getClientProxy().getOzoneManagerClient();
- final String upgradeClientID = "Test-Upgrade-Client-" + UUID.randomUUID();
- UpgradeFinalizer.StatusAndMessages finalizationResponse =
- omClient.finalizeUpgrade(upgradeClientID);
-
- // The status should transition as soon as the client call above returns
- assertTrue(isStarting(finalizationResponse.status()));
- // Wait for the finalization to be marked as done.
- // 10s timeout should be plenty.
- await(POLL_MAX_WAIT_MILLIS, POLL_INTERVAL_MILLIS, () -> {
- final UpgradeFinalizer.StatusAndMessages progress =
- omClient.queryUpgradeFinalizationProgress(
- upgradeClientID, false, false);
- return isDone(progress.status());
- });
- }
-
@Test
// Making this the first test to be run to avoid db key composition headaches
@Order(1)
@@ -369,19 +299,49 @@ public void testKeyMetadata() throws Exception {
// Clean up
assertTrue(fs.delete(file, false));
- // Wait for KeyDeletingService to finish to avoid interfering other tests
- Table deletedTable = omMetadataManager.getDeletedTable();
- GenericTestUtils.waitFor(
- () -> {
- try {
- return deletedTable.isEmpty();
- } catch (IOException e) {
- return false;
- }
- }, 250, 10000);
+ waitForEmptyDeletedTable();
}
}
+ private void waitForEmptyDeletedTable()
+ throws TimeoutException, InterruptedException {
+ // Wait for KeyDeletingService to finish to avoid interfering other tests
+ OMMetadataManager omMetadataManager =
+ cluster.getOzoneManager().getMetadataManager();
+ Table deletedTable = omMetadataManager.getDeletedTable();
+ GenericTestUtils.waitFor(
+ () -> {
+ try {
+ return deletedTable.isEmpty();
+ } catch (IOException e) {
+ return false;
+ }
+ }, 250, 10000);
+ }
+
+ @Test
+ public void testEmptyHsync() throws Exception {
+ // Check that deletedTable should not have keys with the same block as in
+ // keyTable's when a key is hsync()'ed then close()'d.
+
+ // Set the fs.defaultFS
+ final String rootPath = String.format("%s://%s/",
+ OZONE_OFS_URI_SCHEME, CONF.get(OZONE_OM_ADDRESS_KEY));
+ CONF.set(CommonConfigurationKeysPublic.FS_DEFAULT_NAME_KEY, rootPath);
+
+ final String dir = OZONE_ROOT + bucket.getVolumeName()
+ + OZONE_URI_DELIMITER + bucket.getName();
+
+ final Path file = new Path(dir, "file-hsync-empty");
+ try (FileSystem fs = FileSystem.get(CONF)) {
+ try (FSDataOutputStream outputStream = fs.create(file, true)) {
+ outputStream.write(new byte[0], 0, 0);
+ outputStream.hsync();
+ }
+ }
+ waitForEmptyDeletedTable();
+ }
+
@Test
public void testKeyHSyncThenClose() throws Exception {
// Check that deletedTable should not have keys with the same block as in
@@ -566,6 +526,7 @@ private List getOpenKeyInfo(BucketLayout bucketLayout) {
@Test
public void testUncommittedBlocks() throws Exception {
+ waitForEmptyDeletedTable();
// Set the fs.defaultFS
final String rootPath = String.format("%s://%s/",
OZONE_OFS_URI_SCHEME, CONF.get(OZONE_OM_ADDRESS_KEY));
@@ -746,6 +707,99 @@ static void runTestHSync(FileSystem fs, Path file,
}, 500, 3000);
}
+
+ public static Stream concurrentExceptionHandling() {
+ return Stream.of(
+ Arguments.of(4, 1),
+ Arguments.of(4, 4),
+ Arguments.of(8, 4)
+ );
+ }
+
+ @ParameterizedTest
+ @MethodSource("concurrentExceptionHandling")
+ public void testConcurrentExceptionHandling(int syncerThreads, int errors) throws Exception {
+ final String rootPath = String.format("%s://%s/", OZONE_OFS_URI_SCHEME, CONF.get(OZONE_OM_ADDRESS_KEY));
+ CONF.set(CommonConfigurationKeysPublic.FS_DEFAULT_NAME_KEY, rootPath);
+
+ ErrorInjectorImpl errorInjector = new ErrorInjectorImpl();
+ XceiverClientManager.enableErrorInjection(errorInjector);
+
+ final String dir = OZONE_ROOT + bucket.getVolumeName() + OZONE_URI_DELIMITER + bucket.getName();
+
+ try (FileSystem fs = FileSystem.get(CONF)) {
+ final Path file = new Path(dir, "exceptionhandling");
+ byte[] data = new byte[8];
+ ThreadLocalRandom.current().nextBytes(data);
+ int writes;
+ try (FSDataOutputStream out = fs.create(file, true)) {
+ writes = runConcurrentWriteHSyncWithException(file, out, data, syncerThreads, errors, errorInjector);
+ }
+ validateWrittenFile(file, fs, data, writes);
+ fs.delete(file, false);
+ }
+ }
+
+ private int runConcurrentWriteHSyncWithException(Path file,
+ final FSDataOutputStream out, byte[] data, int syncThreadsCount, int errors,
+ ErrorInjectorImpl errorInjector) throws Exception {
+
+ AtomicReference writerException = new AtomicReference<>();
+ AtomicReference syncerException = new AtomicReference<>();
+
+ LOG.info("runConcurrentWriteHSyncWithException {} with size {}", file, data.length);
+ AtomicInteger writes = new AtomicInteger();
+ final long start = Time.monotonicNow();
+
+ Runnable syncer = () -> {
+ while ((Time.monotonicNow() - start < 10000)) {
+ try {
+ out.write(data);
+ writes.incrementAndGet();
+ out.hsync();
+ } catch (Exception e) {
+ LOG.error("Error calling hsync", e);
+ syncerException.compareAndSet(null, e);
+ throw new RuntimeException(e);
+ }
+ }
+ };
+
+ Thread[] syncThreads = new Thread[syncThreadsCount];
+ for (int i = 0; i < syncThreadsCount; i++) {
+ syncThreads[i] = new Thread(syncer);
+ syncThreads[i].setName("Syncer-" + i);
+ syncThreads[i].start();
+ }
+
+ // Inject error at 3rd second.
+ Runnable startErrorInjector = () -> {
+ while ((Time.monotonicNow() - start <= 3000)) {
+ try {
+ Thread.sleep(10);
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ errorInjector.start(errors);
+ LOG.info("Enabled error injection in XceiverClientRatis");
+ };
+
+ new Thread(startErrorInjector).start();
+
+ for (Thread sync : syncThreads) {
+ sync.join();
+ }
+
+ if (syncerException.get() != null) {
+ throw syncerException.get();
+ }
+ if (writerException.get() != null) {
+ throw writerException.get();
+ }
+ return writes.get();
+ }
+
private int runConcurrentWriteHSync(Path file,
final FSDataOutputStream out, byte[] data, int syncThreadsCount) throws Exception {
@@ -1368,4 +1422,33 @@ private Map getAllDeletedKeys(Table= 0) {
+ ContainerProtos.ContainerCommandResponseProto proto = ContainerProtos.ContainerCommandResponseProto.newBuilder()
+ .setResult(ContainerProtos.Result.CLOSED_CONTAINER_IO)
+ .setMessage("Simulated error #" + errorNum)
+ .setCmdType(request.getCmdType())
+ .build();
+ RaftClientReply reply = RaftClientReply.newBuilder()
+ .setSuccess(true)
+ .setMessage(Message.valueOf(proto.toByteString()))
+ .setClientId(clientId)
+ .setServerId(RaftPeerId.getRaftPeerId(pipeline.getLeaderId().toString()))
+ .setGroupId(RaftGroupId.randomId())
+ .build();
+ return reply;
+ }
+
+ return null;
+ }
+ }
}
diff --git a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/fs/ozone/TestHSyncUpgrade.java b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/fs/ozone/TestHSyncUpgrade.java
new file mode 100644
index 00000000000..917ce57fe7d
--- /dev/null
+++ b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/fs/ozone/TestHSyncUpgrade.java
@@ -0,0 +1,240 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.hadoop.fs.ozone;
+
+import org.apache.hadoop.fs.CommonConfigurationKeysPublic;
+import org.apache.hadoop.fs.FSDataOutputStream;
+import org.apache.hadoop.fs.FileSystem;
+import org.apache.hadoop.fs.Path;
+import org.apache.hadoop.hdds.conf.OzoneConfiguration;
+import org.apache.hadoop.hdds.conf.StorageUnit;
+import org.apache.hadoop.hdds.scm.storage.BlockInputStream;
+import org.apache.hadoop.hdds.scm.storage.BlockOutputStream;
+import org.apache.hadoop.hdds.scm.storage.BufferPool;
+import org.apache.hadoop.hdds.utils.IOUtils;
+import org.apache.hadoop.ozone.ClientConfigForTesting;
+import org.apache.hadoop.ozone.MiniOzoneCluster;
+import org.apache.hadoop.ozone.OzoneConfigKeys;
+import org.apache.hadoop.ozone.TestDataUtil;
+import org.apache.hadoop.ozone.client.OzoneBucket;
+import org.apache.hadoop.ozone.client.OzoneClient;
+import org.apache.hadoop.ozone.container.keyvalue.KeyValueHandler;
+import org.apache.hadoop.ozone.container.keyvalue.impl.BlockManagerImpl;
+import org.apache.hadoop.ozone.container.metadata.AbstractDatanodeStore;
+import org.apache.hadoop.ozone.om.exceptions.OMException;
+import org.apache.hadoop.ozone.om.helpers.BucketLayout;
+import org.apache.hadoop.ozone.om.protocol.OzoneManagerProtocol;
+import org.apache.hadoop.ozone.om.service.OpenKeyCleanupService;
+import org.apache.hadoop.ozone.om.upgrade.OMLayoutFeature;
+import org.apache.hadoop.ozone.upgrade.UpgradeFinalizer;
+import org.apache.ozone.test.GenericTestUtils;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.MethodOrderer.OrderAnnotation;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestMethodOrder;
+import org.junit.jupiter.api.Timeout;
+import org.slf4j.event.Level;
+
+import java.io.IOException;
+import java.util.UUID;
+import java.util.concurrent.TimeUnit;
+
+import static org.apache.hadoop.hdds.scm.ScmConfigKeys.OZONE_SCM_RATIS_PIPELINE_LIMIT;
+import static org.apache.hadoop.ozone.OzoneConfigKeys.OZONE_BLOCK_DELETING_SERVICE_INTERVAL;
+import static org.apache.hadoop.ozone.OzoneConsts.OZONE_OFS_URI_SCHEME;
+import static org.apache.hadoop.ozone.OzoneConsts.OZONE_ROOT;
+import static org.apache.hadoop.ozone.OzoneConsts.OZONE_URI_DELIMITER;
+import static org.apache.hadoop.ozone.admin.scm.FinalizeUpgradeCommandUtil.isDone;
+import static org.apache.hadoop.ozone.admin.scm.FinalizeUpgradeCommandUtil.isStarting;
+import static org.apache.hadoop.ozone.om.OMConfigKeys.OZONE_DEFAULT_BUCKET_LAYOUT;
+import static org.apache.hadoop.ozone.om.OMConfigKeys.OZONE_DIR_DELETING_SERVICE_INTERVAL;
+import static org.apache.hadoop.ozone.om.OMConfigKeys.OZONE_OM_ADDRESS_KEY;
+import static org.apache.hadoop.ozone.om.OMConfigKeys.OZONE_OM_LEASE_HARD_LIMIT;
+import static org.apache.hadoop.ozone.om.OMConfigKeys.OZONE_OM_OPEN_KEY_CLEANUP_SERVICE_INTERVAL;
+import static org.apache.hadoop.ozone.om.OMConfigKeys.OZONE_OM_OPEN_KEY_EXPIRE_THRESHOLD;
+import static org.apache.hadoop.ozone.om.OMConfigKeys.OZONE_OM_RATIS_ENABLE_KEY;
+import static org.apache.hadoop.ozone.om.OmUpgradeConfig.ConfigStrings.OZONE_OM_INIT_DEFAULT_LAYOUT_VERSION;
+import static org.apache.hadoop.ozone.om.exceptions.OMException.ResultCodes.NOT_SUPPORTED_OPERATION_PRIOR_FINALIZATION;
+import static org.apache.ozone.test.LambdaTestUtils.await;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+/**
+ * Test HSync upgrade.
+ */
+@Timeout(value = 300)
+@TestMethodOrder(OrderAnnotation.class)
+public class TestHSyncUpgrade {
+ private MiniOzoneCluster cluster;
+ private OzoneBucket bucket;
+
+ private final OzoneConfiguration conf = new OzoneConfiguration();
+ private OzoneClient client;
+ private static final BucketLayout BUCKET_LAYOUT = BucketLayout.FILE_SYSTEM_OPTIMIZED;
+
+ private static final int CHUNK_SIZE = 4 << 12;
+ private static final int FLUSH_SIZE = 3 * CHUNK_SIZE;
+ private static final int MAX_FLUSH_SIZE = 2 * FLUSH_SIZE;
+ private static final int BLOCK_SIZE = 2 * MAX_FLUSH_SIZE;
+ private static final int SERVICE_INTERVAL = 100;
+ private static final int EXPIRE_THRESHOLD_MS = 140;
+
+ private static final int POLL_INTERVAL_MILLIS = 500;
+ private static final int POLL_MAX_WAIT_MILLIS = 120_000;
+
+ @BeforeEach
+ public void init() throws Exception {
+ final BucketLayout layout = BUCKET_LAYOUT;
+
+ conf.setBoolean(OZONE_OM_RATIS_ENABLE_KEY, false);
+ conf.set(OZONE_DEFAULT_BUCKET_LAYOUT, layout.name());
+ conf.setBoolean(OzoneConfigKeys.OZONE_FS_HSYNC_ENABLED, true);
+ conf.setInt(OZONE_SCM_RATIS_PIPELINE_LIMIT, 10);
+ // Reduce KeyDeletingService interval
+ conf.setTimeDuration(OZONE_BLOCK_DELETING_SERVICE_INTERVAL, 100, TimeUnit.MILLISECONDS);
+ conf.setTimeDuration(OZONE_DIR_DELETING_SERVICE_INTERVAL, 100, TimeUnit.MILLISECONDS);
+ conf.setBoolean("ozone.client.incremental.chunk.list", true);
+ conf.setBoolean("ozone.client.stream.putblock.piggybacking", true);
+ conf.setTimeDuration(OZONE_OM_OPEN_KEY_CLEANUP_SERVICE_INTERVAL,
+ SERVICE_INTERVAL, TimeUnit.MILLISECONDS);
+ conf.setTimeDuration(OZONE_OM_OPEN_KEY_EXPIRE_THRESHOLD,
+ EXPIRE_THRESHOLD_MS, TimeUnit.MILLISECONDS);
+ conf.setTimeDuration(OZONE_OM_LEASE_HARD_LIMIT,
+ EXPIRE_THRESHOLD_MS, TimeUnit.MILLISECONDS);
+ conf.set(OzoneConfigKeys.OZONE_OM_LEASE_SOFT_LIMIT, "0s");
+ conf.setInt(OZONE_OM_INIT_DEFAULT_LAYOUT_VERSION, OMLayoutFeature.MULTITENANCY_SCHEMA.layoutVersion());
+
+ ClientConfigForTesting.newBuilder(StorageUnit.BYTES)
+ .setBlockSize(BLOCK_SIZE)
+ .setChunkSize(CHUNK_SIZE)
+ .setStreamBufferFlushSize(FLUSH_SIZE)
+ .setStreamBufferMaxSize(MAX_FLUSH_SIZE)
+ .setDataStreamBufferFlushSize(MAX_FLUSH_SIZE)
+ .setDataStreamMinPacketSize(CHUNK_SIZE)
+ .setDataStreamWindowSize(5 * CHUNK_SIZE)
+ .applyTo(conf);
+
+ cluster = MiniOzoneCluster.newBuilder(conf)
+ .setNumDatanodes(5)
+ .build();
+ cluster.waitForClusterToBeReady();
+ client = cluster.newClient();
+
+ // create a volume and a bucket to be used by OzoneFileSystem
+ bucket = TestDataUtil.createVolumeAndBucket(client, layout);
+
+ // Enable DEBUG level logging for relevant classes
+ GenericTestUtils.setLogLevel(BlockManagerImpl.LOG, Level.DEBUG);
+ GenericTestUtils.setLogLevel(AbstractDatanodeStore.LOG, Level.DEBUG);
+ GenericTestUtils.setLogLevel(BlockOutputStream.LOG, Level.DEBUG);
+ GenericTestUtils.setLogLevel(BlockInputStream.LOG, Level.DEBUG);
+ GenericTestUtils.setLogLevel(KeyValueHandler.LOG, Level.DEBUG);
+
+ GenericTestUtils.setLogLevel(BufferPool.LOG, Level.DEBUG);
+
+ OpenKeyCleanupService openKeyCleanupService =
+ (OpenKeyCleanupService) cluster.getOzoneManager().getKeyManager()
+ .getOpenKeyCleanupService();
+ openKeyCleanupService.suspend();
+ }
+
+ @AfterEach
+ public void teardown() {
+ IOUtils.closeQuietly(client);
+ if (cluster != null) {
+ cluster.shutdown();
+ }
+ }
+
+ @Test
+ public void upgrade() throws Exception {
+ preFinalizationChecks();
+ finalizeOMUpgrade();
+ }
+
+ private void preFinalizationChecks() throws IOException {
+ final String rootPath = String.format("%s://%s/",
+ OZONE_OFS_URI_SCHEME, conf.get(OZONE_OM_ADDRESS_KEY));
+ conf.set(CommonConfigurationKeysPublic.FS_DEFAULT_NAME_KEY, rootPath);
+
+ final String dir = OZONE_ROOT + bucket.getVolumeName()
+ + OZONE_URI_DELIMITER + bucket.getName();
+
+ final Path file = new Path(dir, "pre-finalization");
+ try (RootedOzoneFileSystem fs = (RootedOzoneFileSystem)FileSystem.get(conf)) {
+ try (FSDataOutputStream outputStream = fs.create(file, true)) {
+ OMException omException = assertThrows(OMException.class, outputStream::hsync);
+ assertFinalizationExceptionForHsync(omException);
+ }
+ final OzoneManagerProtocol omClient = client.getObjectStore()
+ .getClientProxy().getOzoneManagerClient();
+ OMException omException = assertThrows(OMException.class,
+ () -> omClient.listOpenFiles("", 100, ""));
+ assertFinalizationException(omException);
+
+ omException = assertThrows(OMException.class,
+ () -> fs.recoverLease(file));
+ assertFinalizationException(omException);
+
+ fs.delete(file, false);
+ }
+ }
+
+ private void assertFinalizationExceptionForHsync(OMException omException) {
+ assertEquals(NOT_SUPPORTED_OPERATION_PRIOR_FINALIZATION,
+ omException.getResult());
+ assertThat(omException.getMessage())
+ .contains("Cluster does not have the hsync support feature finalized yet");
+ }
+
+ private void assertFinalizationException(OMException omException) {
+ assertEquals(NOT_SUPPORTED_OPERATION_PRIOR_FINALIZATION,
+ omException.getResult());
+ assertThat(omException.getMessage())
+ .contains("cannot be invoked before finalization.");
+ }
+
+ /**
+ * Trigger OM upgrade finalization from the client and block until completion
+ * (status FINALIZATION_DONE).
+ */
+ private void finalizeOMUpgrade() throws Exception {
+ // Trigger OM upgrade finalization. Ref: FinalizeUpgradeSubCommand#call
+ final OzoneManagerProtocol omClient = client.getObjectStore()
+ .getClientProxy().getOzoneManagerClient();
+ final String upgradeClientID = "Test-Upgrade-Client-" + UUID.randomUUID();
+ UpgradeFinalizer.StatusAndMessages finalizationResponse =
+ omClient.finalizeUpgrade(upgradeClientID);
+
+ // The status should transition as soon as the client call above returns
+ assertTrue(isStarting(finalizationResponse.status()));
+ // Wait for the finalization to be marked as done.
+ // 10s timeout should be plenty.
+ await(POLL_MAX_WAIT_MILLIS, POLL_INTERVAL_MILLIS, () -> {
+ final UpgradeFinalizer.StatusAndMessages progress =
+ omClient.queryUpgradeFinalizationProgress(
+ upgradeClientID, false, false);
+ return isDone(progress.status());
+ });
+ }
+
+}
diff --git a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/fs/ozone/TestLeaseRecovery.java b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/fs/ozone/TestLeaseRecovery.java
index 6ec233fc35b..a4a9bcff470 100644
--- a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/fs/ozone/TestLeaseRecovery.java
+++ b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/fs/ozone/TestLeaseRecovery.java
@@ -45,6 +45,7 @@
import org.apache.hadoop.ozone.om.helpers.BucketLayout;
import org.apache.hadoop.utils.FaultInjectorImpl;
import org.apache.ozone.test.GenericTestUtils;
+import org.apache.ozone.test.tag.Flaky;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -82,6 +83,7 @@
* Test cases for recoverLease() API.
*/
@Timeout(300)
+@Flaky("HDDS-11323")
public class TestLeaseRecovery {
private MiniOzoneCluster cluster;
diff --git a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/hdds/scm/pipeline/TestPipelineManagerMXBean.java b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/hdds/scm/pipeline/TestPipelineManagerMXBean.java
index b6e85ab942d..75d860d951b 100644
--- a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/hdds/scm/pipeline/TestPipelineManagerMXBean.java
+++ b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/hdds/scm/pipeline/TestPipelineManagerMXBean.java
@@ -21,6 +21,7 @@
import org.apache.hadoop.hdds.conf.OzoneConfiguration;
import org.apache.hadoop.ozone.MiniOzoneCluster;
import org.apache.ozone.test.GenericTestUtils;
+import org.apache.ozone.test.tag.Flaky;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -61,6 +62,7 @@ public void init()
*
* @throws Exception
*/
+ @Flaky("HDDS-11359")
@Test
public void testPipelineInfo() throws Exception {
ObjectName bean = new ObjectName(
diff --git a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/hdds/utils/ClusterContainersUtil.java b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/hdds/utils/ClusterContainersUtil.java
index e7e0337b5f9..bf20b4ecc0b 100644
--- a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/hdds/utils/ClusterContainersUtil.java
+++ b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/hdds/utils/ClusterContainersUtil.java
@@ -19,12 +19,12 @@
import com.google.common.base.Preconditions;
import org.apache.commons.io.FileUtils;
+import org.apache.hadoop.hdds.client.BlockID;
import org.apache.hadoop.ozone.HddsDatanodeService;
import org.apache.hadoop.ozone.MiniOzoneCluster;
import org.apache.hadoop.ozone.client.OzoneKey;
import org.apache.hadoop.ozone.client.OzoneKeyDetails;
import org.apache.hadoop.ozone.container.common.helpers.BlockData;
-import org.apache.hadoop.ozone.container.common.interfaces.BlockIterator;
import org.apache.hadoop.ozone.container.common.interfaces.Container;
import org.apache.hadoop.ozone.container.common.interfaces.DBHandle;
import org.apache.hadoop.ozone.container.keyvalue.KeyValueContainerData;
@@ -65,18 +65,10 @@ public static File getChunksLocationPath(MiniOzoneCluster cluster, Container con
// the container.
KeyValueContainerData containerData =
(KeyValueContainerData) container.getContainerData();
- try (DBHandle db = BlockUtils.getDB(containerData, cluster.getConf());
- BlockIterator keyValueBlockIterator =
- db.getStore().getBlockIterator(containerID)) {
- // Find the block corresponding to the key we put. We use the localID of
- // the BlockData to identify out key.
- BlockData blockData = null;
- while (keyValueBlockIterator.hasNext()) {
- blockData = keyValueBlockIterator.nextBlock();
- if (blockData.getBlockID().getLocalID() == localID) {
- break;
- }
- }
+ try (DBHandle db = BlockUtils.getDB(containerData, cluster.getConf())) {
+ BlockID blockID = new BlockID(containerID, localID);
+ String blockKey = containerData.getBlockKey(localID);
+ BlockData blockData = db.getStore().getBlockByID(blockID, blockKey);
assertNotNull(blockData, "Block not found");
// Get the location of the chunk file
diff --git a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/TestSecureOzoneCluster.java b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/TestSecureOzoneCluster.java
index 2b29701cf79..4f41d516153 100644
--- a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/TestSecureOzoneCluster.java
+++ b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/TestSecureOzoneCluster.java
@@ -1449,11 +1449,12 @@ private static X509Certificate signX509Cert(
addIpAndDnsDataToBuilder(csrBuilder);
LocalDateTime start = LocalDateTime.now();
Duration certDuration = conf.getDefaultCertDuration();
+ //TODO: generateCSR!
return approver.sign(conf, rootKeyPair.getPrivate(), rootCert,
Date.from(start.atZone(ZoneId.systemDefault()).toInstant()),
Date.from(start.plus(certDuration)
.atZone(ZoneId.systemDefault()).toInstant()),
- csrBuilder.build(), "test", clusterId,
+ csrBuilder.build().generateCSR(), "test", clusterId,
String.valueOf(System.nanoTime()));
}
diff --git a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/client/rpc/AbstractTestECKeyOutputStream.java b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/client/rpc/AbstractTestECKeyOutputStream.java
index b40b0bbcc62..766ed09bccd 100644
--- a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/client/rpc/AbstractTestECKeyOutputStream.java
+++ b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/client/rpc/AbstractTestECKeyOutputStream.java
@@ -16,6 +16,7 @@
*/
package org.apache.hadoop.ozone.client.rpc;
+import org.apache.commons.lang3.NotImplementedException;
import org.apache.hadoop.hdds.HddsConfigKeys;
import org.apache.hadoop.hdds.client.DefaultReplicationConfig;
import org.apache.hadoop.hdds.client.ECReplicationConfig;
@@ -67,6 +68,7 @@
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
+import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.fail;
/**
@@ -123,6 +125,8 @@ protected static void init(boolean zeroCopyEnabled) throws Exception {
conf.setBoolean(OzoneConfigKeys.OZONE_EC_GRPC_ZERO_COPY_ENABLED,
zeroCopyEnabled);
conf.setInt(ScmConfigKeys.OZONE_SCM_RATIS_PIPELINE_LIMIT, 10);
+ // "Enable" hsync to verify that hsync would be blocked by ECKeyOutputStream
+ conf.setBoolean(OzoneConfigKeys.OZONE_FS_HSYNC_ENABLED, true);
ClientConfigForTesting.newBuilder(StorageUnit.BYTES)
.setBlockSize(blockSize)
@@ -469,4 +473,18 @@ private byte[] getInputBytes(int offset, int bufferChunks, int numChunks) {
return inputData;
}
+ @Test
+ public void testBlockedHflushAndHsync() throws Exception {
+ // Expect ECKeyOutputStream hflush and hsync calls to throw exception
+ try (OzoneOutputStream oOut = TestHelper.createKey(
+ keyString, new ECReplicationConfig(3, 2, ECReplicationConfig.EcCodec.RS, chunkSize),
+ inputSize, objectStore, volumeName, bucketName)) {
+ assertInstanceOf(ECKeyOutputStream.class, oOut.getOutputStream());
+ KeyOutputStream kOut = (KeyOutputStream) oOut.getOutputStream();
+
+ assertThrows(NotImplementedException.class, () -> kOut.hflush());
+ assertThrows(NotImplementedException.class, () -> kOut.hsync());
+ }
+ }
+
}
diff --git a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/client/rpc/OzoneRpcClientTests.java b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/client/rpc/OzoneRpcClientTests.java
index 30597fc3e77..eb9f35f518c 100644
--- a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/client/rpc/OzoneRpcClientTests.java
+++ b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/client/rpc/OzoneRpcClientTests.java
@@ -4908,6 +4908,12 @@ public void testParallelDeleteBucketAndCreateKey() throws IOException,
assertThat(omSMLog.getOutput()).contains("Failed to write, Exception occurred");
}
+ @Test
+ public void testGetServerDefaults() throws IOException {
+ assertNotNull(getClient().getProxy().getServerDefaults());
+ assertNull(getClient().getProxy().getServerDefaults().getKeyProviderUri());
+ }
+
private static class OMRequestHandlerPauseInjector extends FaultInjector {
private CountDownLatch ready;
private CountDownLatch wait;
diff --git a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/client/rpc/TestBlockOutputStream.java b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/client/rpc/TestBlockOutputStream.java
index 2a6b2246b9c..8810bab5190 100644
--- a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/client/rpc/TestBlockOutputStream.java
+++ b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/client/rpc/TestBlockOutputStream.java
@@ -48,6 +48,7 @@
import org.apache.hadoop.ozone.client.io.OzoneOutputStream;
import org.apache.hadoop.ozone.container.TestHelper;
+import org.apache.ozone.test.tag.Flaky;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.TestInstance;
@@ -661,6 +662,7 @@ void testWriteExactlyMaxFlushSize(boolean flushDelay, boolean enablePiggybacking
@ParameterizedTest
@MethodSource("clientParameters")
+ @Flaky("HDDS-11325")
void testWriteMoreThanMaxFlushSize(boolean flushDelay, boolean enablePiggybacking) throws Exception {
OzoneClientConfig config = newClientConfig(cluster.getConf(), flushDelay, enablePiggybacking);
try (OzoneClient client = newClient(cluster.getConf(), config)) {
@@ -698,7 +700,8 @@ void testWriteMoreThanMaxFlushSize(boolean flushDelay, boolean enablePiggybackin
assertInstanceOf(RatisBlockOutputStream.class,
keyOutputStream.getStreamEntries().get(0).getOutputStream());
- assertEquals(4, blockOutputStream.getBufferPool().getSize());
+ assertThat(blockOutputStream.getBufferPool().getSize())
+ .isLessThanOrEqualTo(4);
// writtenDataLength as well flushedDataLength will be updated here
assertEquals(dataLength, blockOutputStream.getWrittenDataLength());
@@ -727,7 +730,8 @@ void testWriteMoreThanMaxFlushSize(boolean flushDelay, boolean enablePiggybackin
// Since the data in the buffer is already flushed, flush here will have
// no impact on the counters and data structures
- assertEquals(4, blockOutputStream.getBufferPool().getSize());
+ assertThat(blockOutputStream.getBufferPool().getSize())
+ .isLessThanOrEqualTo(4);
assertEquals(dataLength, blockOutputStream.getWrittenDataLength());
// dataLength > MAX_FLUSH_SIZE
assertEquals(flushDelay ? MAX_FLUSH_SIZE : dataLength,
diff --git a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/client/rpc/TestBlockOutputStreamWithFailures.java b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/client/rpc/TestBlockOutputStreamWithFailures.java
index 8d69da3ef3e..f823add57bd 100644
--- a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/client/rpc/TestBlockOutputStreamWithFailures.java
+++ b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/client/rpc/TestBlockOutputStreamWithFailures.java
@@ -93,6 +93,7 @@ private static Stream clientParameters() {
@ParameterizedTest
@MethodSource("clientParameters")
+ @Flaky("HDDS-11325")
void testContainerClose(boolean flushDelay, boolean enablePiggybacking) throws Exception {
OzoneClientConfig config = newClientConfig(cluster.getConf(), flushDelay, enablePiggybacking);
try (OzoneClient client = newClient(cluster.getConf(), config)) {
diff --git a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/client/rpc/TestCommitInRatis.java b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/client/rpc/TestCommitInRatis.java
index f7fbbf37c52..4ff671df616 100644
--- a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/client/rpc/TestCommitInRatis.java
+++ b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/client/rpc/TestCommitInRatis.java
@@ -163,7 +163,7 @@ public void test2WayCommitForRetryfailure(RaftProtos.ReplicationLevel watchType)
reply.getResponse().get();
assertEquals(3, ratisClient.getCommitInfoMap().size());
// wait for the container to be created on all the nodes
- xceiverClient.watchForCommit(reply.getLogIndex());
+ xceiverClient.watchForCommit(reply.getLogIndex()).get();
for (HddsDatanodeService dn : cluster.getHddsDatanodes()) {
// shutdown the ratis follower
if (RatisTestHelper.isRatisFollower(dn, pipeline)) {
@@ -175,7 +175,7 @@ public void test2WayCommitForRetryfailure(RaftProtos.ReplicationLevel watchType)
.getCloseContainer(pipeline,
container1.getContainerInfo().getContainerID()));
reply.getResponse().get();
- xceiverClient.watchForCommit(reply.getLogIndex());
+ xceiverClient.watchForCommit(reply.getLogIndex()).get();
if (watchType == RaftProtos.ReplicationLevel.ALL_COMMITTED) {
// commitInfo Map will be reduced to 2 here
diff --git a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/client/rpc/TestMultiBlockWritesWithDnFailures.java b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/client/rpc/TestMultiBlockWritesWithDnFailures.java
index 34f85d8e992..4c558c3d77a 100644
--- a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/client/rpc/TestMultiBlockWritesWithDnFailures.java
+++ b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/client/rpc/TestMultiBlockWritesWithDnFailures.java
@@ -42,6 +42,7 @@
import org.apache.hadoop.ozone.om.helpers.OmKeyArgs;
import org.apache.hadoop.ozone.om.helpers.OmKeyInfo;
import org.apache.hadoop.ozone.om.helpers.OmKeyLocationInfo;
+import org.apache.ozone.test.tag.Flaky;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.Timeout;
@@ -178,6 +179,7 @@ public void testMultiBlockWritesWithDnFailures() throws Exception {
validateData(keyName, data.concat(data).getBytes(UTF_8));
}
+ @Flaky("HDDS-11355")
@Test
public void testMultiBlockWritesWithIntermittentDnFailures()
throws Exception {
diff --git a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/client/rpc/TestSecureOzoneRpcClient.java b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/client/rpc/TestSecureOzoneRpcClient.java
index 773f6be966b..958a37380cf 100644
--- a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/client/rpc/TestSecureOzoneRpcClient.java
+++ b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/client/rpc/TestSecureOzoneRpcClient.java
@@ -99,6 +99,8 @@
*/
class TestSecureOzoneRpcClient extends OzoneRpcClientTests {
+ private static String keyProviderUri = "kms://http@kms:9600/kms";
+
@BeforeAll
public static void init() throws Exception {
File testDir = GenericTestUtils.getTestDir(
@@ -120,6 +122,8 @@ public static void init() throws Exception {
conf.set(OMConfigKeys.OZONE_DEFAULT_BUCKET_LAYOUT,
OMConfigKeys.OZONE_BUCKET_LAYOUT_OBJECT_STORE);
conf.setBoolean(OzoneConfigKeys.OZONE_FS_HSYNC_ENABLED, true);
+ conf.set(CommonConfigurationKeysPublic.HADOOP_SECURITY_KEY_PROVIDER_PATH,
+ keyProviderUri);
MiniOzoneCluster.Builder builder = MiniOzoneCluster.newBuilder(conf)
.setCertificateClient(certificateClientTest)
.setSecretKeyClient(new SecretKeyTestClient());
@@ -433,6 +437,13 @@ public void testS3Auth() throws Exception {
public void testZReadKeyWithUnhealthyContainerReplica() {
}
+ @Test
+ public void testGetServerDefaults() throws IOException {
+ assertNotNull(getClient().getProxy().getServerDefaults());
+ assertEquals(keyProviderUri,
+ getClient().getProxy().getServerDefaults().getKeyProviderUri());
+ }
+
@AfterAll
public static void shutdown() throws IOException {
shutdownCluster();
diff --git a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/client/rpc/TestWatchForCommit.java b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/client/rpc/TestWatchForCommit.java
index f42969e67f0..bec14b23b0f 100644
--- a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/client/rpc/TestWatchForCommit.java
+++ b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/client/rpc/TestWatchForCommit.java
@@ -291,7 +291,7 @@ public void testWatchForCommitForRetryfailure(RaftProtos.ReplicationLevel watchT
// as well as there is no logIndex generate in Ratis.
// The basic idea here is just to test if its throws an exception.
ExecutionException e = assertThrows(ExecutionException.class,
- () -> xceiverClient.watchForCommit(index + RandomUtils.nextInt(0, 100) + 10));
+ () -> xceiverClient.watchForCommit(index + RandomUtils.nextInt(0, 100) + 10).get());
// since the timeout value is quite long, the watch request will either
// fail with NotReplicated exceptio, RetryFailureException or
// RuntimeException
@@ -348,7 +348,7 @@ public void test2WayCommitForTimeoutException(RaftProtos.ReplicationLevel watchT
.getCloseContainer(pipeline,
container1.getContainerInfo().getContainerID()));
reply.getResponse().get();
- xceiverClient.watchForCommit(reply.getLogIndex());
+ xceiverClient.watchForCommit(reply.getLogIndex()).get();
// commitInfo Map will be reduced to 2 here
if (watchType == RaftProtos.ReplicationLevel.ALL_COMMITTED) {
@@ -392,9 +392,8 @@ public void testWatchForCommitForGroupMismatchException() throws Exception {
// just watch for a log index which in not updated in the commitInfo Map
// as well as there is no logIndex generate in Ratis.
// The basic idea here is just to test if its throws an exception.
- Exception e =
- assertThrows(Exception.class,
- () -> xceiverClient.watchForCommit(reply.getLogIndex() + RandomUtils.nextInt(0, 100) + 10));
+ final Exception e = assertThrows(Exception.class,
+ () -> xceiverClient.watchForCommit(reply.getLogIndex() + RandomUtils.nextInt(0, 100) + 10).get());
assertInstanceOf(GroupMismatchException.class, HddsClientUtils.checkForException(e));
} finally {
clientManager.releaseClient(xceiverClient, false);
diff --git a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/container/common/statemachine/commandhandler/TestDeleteContainerHandler.java b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/container/common/statemachine/commandhandler/TestDeleteContainerHandler.java
index 00654d943f7..192c933f53c 100644
--- a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/container/common/statemachine/commandhandler/TestDeleteContainerHandler.java
+++ b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/container/common/statemachine/commandhandler/TestDeleteContainerHandler.java
@@ -557,23 +557,32 @@ private void clearBlocksTable(Container container) throws IOException {
= BlockUtils.getDB(
(KeyValueContainerData) container.getContainerData(),
conf)) {
- List extends Table.KeyValue>
- blocks = dbHandle.getStore().getBlockDataTable().getRangeKVs(
- ((KeyValueContainerData) container.getContainerData()).
- startKeyEmpty(),
- Integer.MAX_VALUE,
- ((KeyValueContainerData) container.getContainerData()).
- containerPrefix(),
- ((KeyValueContainerData) container.getContainerData()).
- getUnprefixedKeyFilter());
- try (BatchOperation batch = dbHandle.getStore().getBatchHandler()
- .initBatchOperation()) {
- for (Table.KeyValue kv : blocks) {
- String blk = kv.getKey();
- dbHandle.getStore().getBlockDataTable().deleteWithBatch(batch, blk);
- }
- dbHandle.getStore().getBatchHandler().commitBatchOperation(batch);
+ Table table = dbHandle.getStore().getBlockDataTable();
+ clearTable(dbHandle, table, container);
+
+ table = dbHandle.getStore().getLastChunkInfoTable();
+ clearTable(dbHandle, table, container);
+ }
+ }
+
+ private void clearTable(DBHandle dbHandle, Table table, Container container)
+ throws IOException {
+ List extends Table.KeyValue>
+ blocks = table.getRangeKVs(
+ ((KeyValueContainerData) container.getContainerData()).
+ startKeyEmpty(),
+ Integer.MAX_VALUE,
+ ((KeyValueContainerData) container.getContainerData()).
+ containerPrefix(),
+ ((KeyValueContainerData) container.getContainerData()).
+ getUnprefixedKeyFilter());
+ try (BatchOperation batch = dbHandle.getStore().getBatchHandler()
+ .initBatchOperation()) {
+ for (Table.KeyValue kv : blocks) {
+ String blk = kv.getKey();
+ table.deleteWithBatch(batch, blk);
}
+ dbHandle.getStore().getBatchHandler().commitBatchOperation(batch);
}
}
diff --git a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/container/common/transport/server/ratis/TestCSMMetrics.java b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/container/common/transport/server/ratis/TestCSMMetrics.java
index 0fd31bb4b72..e68831b494f 100644
--- a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/container/common/transport/server/ratis/TestCSMMetrics.java
+++ b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/container/common/transport/server/ratis/TestCSMMetrics.java
@@ -189,7 +189,7 @@ static XceiverServerRatis newXceiverServerRatis(
conf.set(OzoneConfigKeys.HDDS_CONTAINER_RATIS_DATANODE_STORAGE_DIR, dir);
final ContainerDispatcher dispatcher = new TestContainerDispatcher();
- return XceiverServerRatis.newXceiverServerRatis(dn, conf, dispatcher,
+ return XceiverServerRatis.newXceiverServerRatis(null, dn, conf, dispatcher,
new ContainerController(new ContainerSet(1000), Maps.newHashMap()),
null, null);
}
diff --git a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/container/metrics/TestContainerMetrics.java b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/container/metrics/TestContainerMetrics.java
index 068cb01a967..f55912b26b0 100644
--- a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/container/metrics/TestContainerMetrics.java
+++ b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/container/metrics/TestContainerMetrics.java
@@ -21,7 +21,6 @@
import java.io.IOException;
import java.nio.file.Path;
import java.util.List;
-import java.util.Map;
import java.util.UUID;
import org.apache.commons.io.FileUtils;
@@ -48,7 +47,6 @@
import org.apache.hadoop.ozone.container.common.impl.ContainerSet;
import org.apache.hadoop.ozone.container.common.impl.HddsDispatcher;
import org.apache.hadoop.ozone.container.common.interfaces.ContainerDispatcher;
-import org.apache.hadoop.ozone.container.common.interfaces.Handler;
import org.apache.hadoop.ozone.container.common.statemachine.StateContext;
import org.apache.hadoop.ozone.container.common.transport.server.XceiverServerGrpc;
import org.apache.hadoop.ozone.container.common.transport.server.XceiverServerSpi;
@@ -148,18 +146,7 @@ private HddsDispatcher createDispatcher(DatanodeDetails dd, VolumeSet volumeSet)
ContainerSet containerSet = new ContainerSet(1000);
StateContext context = ContainerTestUtils.getMockContext(
dd, CONF);
- ContainerMetrics metrics = ContainerMetrics.create(CONF);
- Map handlers = Maps.newHashMap();
- for (ContainerProtos.ContainerType containerType :
- ContainerProtos.ContainerType.values()) {
- handlers.put(containerType,
- Handler.getHandlerForContainerType(containerType, CONF,
- context.getParent().getDatanodeDetails().getUuidString(),
- containerSet, volumeSet, metrics,
- c -> { }));
- }
- HddsDispatcher dispatcher = new HddsDispatcher(CONF, containerSet,
- volumeSet, handlers, context, metrics, null);
+ HddsDispatcher dispatcher = ContainerTestUtils.getHddsDispatcher(CONF, containerSet, volumeSet, context);
StorageVolumeUtil.getHddsVolumesList(volumeSet.getVolumesList())
.forEach(hddsVolume -> hddsVolume.setDbParentDir(tempDir.toFile()));
dispatcher.setClusterId(UUID.randomUUID().toString());
@@ -253,7 +240,7 @@ private XceiverServerSpi newXceiverServerRatis(DatanodeDetails dn, MutableVolume
CONF.set(OzoneConfigKeys.HDDS_CONTAINER_RATIS_DATANODE_STORAGE_DIR, dir);
final ContainerDispatcher dispatcher = createDispatcher(dn,
volumeSet);
- return XceiverServerRatis.newXceiverServerRatis(dn, CONF, dispatcher,
+ return XceiverServerRatis.newXceiverServerRatis(null, dn, CONF, dispatcher,
new ContainerController(new ContainerSet(1000), Maps.newHashMap()),
null, null);
}
diff --git a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/container/ozoneimpl/TestOzoneContainerWithTLS.java b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/container/ozoneimpl/TestOzoneContainerWithTLS.java
index e06e8b5a00f..3ac0cd4346e 100644
--- a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/container/ozoneimpl/TestOzoneContainerWithTLS.java
+++ b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/container/ozoneimpl/TestOzoneContainerWithTLS.java
@@ -386,7 +386,7 @@ private OzoneContainer createAndStartOzoneContainerInstance() {
try {
StateContext stateContext = ContainerTestUtils.getMockContext(dn, conf);
container = new OzoneContainer(
- dn, conf, stateContext, caClient, keyClient);
+ null, dn, conf, stateContext, caClient, keyClient);
MutableVolumeSet volumeSet = container.getVolumeSet();
StorageVolumeUtil.getHddsVolumesList(volumeSet.getVolumesList())
.forEach(hddsVolume -> hddsVolume.setDbParentDir(tempFolder.toFile()));
diff --git a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/container/ozoneimpl/TestSecureOzoneContainer.java b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/container/ozoneimpl/TestSecureOzoneContainer.java
index 5585696dfc3..92d716f7a40 100644
--- a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/container/ozoneimpl/TestSecureOzoneContainer.java
+++ b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/container/ozoneimpl/TestSecureOzoneContainer.java
@@ -137,7 +137,7 @@ void testCreateOzoneContainer(boolean requireToken, boolean hasToken,
conf.setBoolean(OzoneConfigKeys.HDDS_CONTAINER_IPC_RANDOM_PORT, false);
DatanodeDetails dn = MockDatanodeDetails.randomDatanodeDetails();
- container = new OzoneContainer(dn, conf, ContainerTestUtils
+ container = new OzoneContainer(null, dn, conf, ContainerTestUtils
.getMockContext(dn, conf), caClient, secretKeyClient);
MutableVolumeSet volumeSet = container.getVolumeSet();
StorageVolumeUtil.getHddsVolumesList(volumeSet.getVolumesList())
diff --git a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/container/server/TestContainerServer.java b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/container/server/TestContainerServer.java
index 630c4d31495..27e85501662 100644
--- a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/container/server/TestContainerServer.java
+++ b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/container/server/TestContainerServer.java
@@ -48,7 +48,6 @@
import org.apache.hadoop.ozone.RatisTestHelper;
import org.apache.hadoop.ozone.container.ContainerTestHelper;
import org.apache.hadoop.ozone.container.common.ContainerTestUtils;
-import org.apache.hadoop.ozone.container.common.helpers.ContainerMetrics;
import org.apache.hadoop.ozone.container.common.impl.ContainerSet;
import org.apache.hadoop.ozone.container.common.impl.HddsDispatcher;
import org.apache.hadoop.ozone.container.common.interfaces.ContainerDispatcher;
@@ -132,7 +131,7 @@ static XceiverServerRatis newXceiverServerRatis(
conf.set(OzoneConfigKeys.HDDS_CONTAINER_RATIS_DATANODE_STORAGE_DIR, dir);
final ContainerDispatcher dispatcher = new TestContainerDispatcher();
- return XceiverServerRatis.newXceiverServerRatis(dn, conf, dispatcher,
+ return XceiverServerRatis.newXceiverServerRatis(null, dn, conf, dispatcher,
new ContainerController(new ContainerSet(1000), Maps.newHashMap()),
caClient, null);
}
@@ -200,19 +199,7 @@ private HddsDispatcher createDispatcher(DatanodeDetails dd, UUID scmId,
StorageVolumeUtil.getHddsVolumesList(volumeSet.getVolumesList())
.forEach(hddsVolume -> hddsVolume.setDbParentDir(tempDir.toFile()));
StateContext context = ContainerTestUtils.getMockContext(dd, conf);
- ContainerMetrics metrics = ContainerMetrics.create(conf);
- Map handlers = Maps.newHashMap();
- for (ContainerProtos.ContainerType containerType :
- ContainerProtos.ContainerType.values()) {
- handlers.put(containerType,
- Handler.getHandlerForContainerType(containerType, conf,
- dd.getUuid().toString(),
- containerSet, volumeSet, metrics,
- c -> {
- }));
- }
- HddsDispatcher hddsDispatcher = new HddsDispatcher(
- conf, containerSet, volumeSet, handlers, context, metrics, null);
+ HddsDispatcher hddsDispatcher = ContainerTestUtils.getHddsDispatcher(conf, containerSet, volumeSet, context);
hddsDispatcher.setClusterId(scmId.toString());
return hddsDispatcher;
}
diff --git a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/container/server/TestSecureContainerServer.java b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/container/server/TestSecureContainerServer.java
index 8044685bb74..cae7f6bb59e 100644
--- a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/container/server/TestSecureContainerServer.java
+++ b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/container/server/TestSecureContainerServer.java
@@ -25,7 +25,6 @@
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.List;
-import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
@@ -57,11 +56,9 @@
import org.apache.hadoop.ozone.RatisTestHelper;
import org.apache.hadoop.ozone.client.SecretKeyTestClient;
import org.apache.hadoop.ozone.container.common.ContainerTestUtils;
-import org.apache.hadoop.ozone.container.common.helpers.ContainerMetrics;
import org.apache.hadoop.ozone.container.common.impl.ContainerSet;
import org.apache.hadoop.ozone.container.common.impl.HddsDispatcher;
import org.apache.hadoop.ozone.container.common.interfaces.ContainerDispatcher;
-import org.apache.hadoop.ozone.container.common.interfaces.Handler;
import org.apache.hadoop.ozone.container.common.statemachine.StateContext;
import org.apache.hadoop.ozone.container.common.transport.server.XceiverServerGrpc;
import org.apache.hadoop.ozone.container.common.transport.server.XceiverServerSpi;
@@ -183,18 +180,7 @@ private HddsDispatcher createDispatcher(DatanodeDetails dd, UUID scmId,
StorageVolumeUtil.getHddsVolumesList(volumeSet.getVolumesList())
.forEach(hddsVolume -> hddsVolume.setDbParentDir(tempDir.toFile()));
StateContext context = ContainerTestUtils.getMockContext(dd, conf);
- ContainerMetrics metrics = ContainerMetrics.create(conf);
- Map handlers = Maps.newHashMap();
- for (ContainerProtos.ContainerType containerType :
- ContainerProtos.ContainerType.values()) {
- handlers.put(containerType,
- Handler.getHandlerForContainerType(containerType, conf,
- dd.getUuid().toString(),
- containerSet, volumeSet, metrics,
- c -> { }));
- }
- HddsDispatcher hddsDispatcher = new HddsDispatcher(
- conf, containerSet, volumeSet, handlers, context, metrics,
+ HddsDispatcher hddsDispatcher = ContainerTestUtils.getHddsDispatcher(conf, containerSet, volumeSet, context,
TokenVerifier.create(new SecurityConfig(conf), secretKeyClient));
hddsDispatcher.setClusterId(scmId.toString());
return hddsDispatcher;
@@ -218,7 +204,7 @@ XceiverServerRatis newXceiverServerRatis(
conf.set(OzoneConfigKeys.HDDS_CONTAINER_RATIS_DATANODE_STORAGE_DIR, dir);
final ContainerDispatcher dispatcher = createDispatcher(dn,
UUID.randomUUID(), conf);
- return XceiverServerRatis.newXceiverServerRatis(dn, conf, dispatcher,
+ return XceiverServerRatis.newXceiverServerRatis(null, dn, conf, dispatcher,
new ContainerController(new ContainerSet(1000), Maps.newHashMap()),
caClient, null);
}
diff --git a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/freon/TestDNRPCLoadGenerator.java b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/freon/TestDNRPCLoadGenerator.java
index f209783c745..33d59f101eb 100644
--- a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/freon/TestDNRPCLoadGenerator.java
+++ b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/freon/TestDNRPCLoadGenerator.java
@@ -22,7 +22,8 @@
import org.apache.hadoop.hdds.conf.OzoneConfiguration;
import org.apache.hadoop.hdds.protocol.proto.HddsProtos;
import org.apache.hadoop.hdds.ratis.conf.RatisClientConfig;
-import org.apache.hadoop.hdds.scm.XceiverClientManager;
+import org.apache.hadoop.hdds.scm.XceiverClientCreator;
+import org.apache.hadoop.hdds.scm.XceiverClientFactory;
import org.apache.hadoop.hdds.scm.XceiverClientSpi;
import org.apache.hadoop.hdds.scm.container.common.helpers.ContainerWithPipeline;
import org.apache.hadoop.hdds.scm.protocolPB.StorageContainerLocationProtocolClientSideTranslatorPB;
@@ -79,11 +80,11 @@ private static void startCluster(OzoneConfiguration conf) throws Exception {
storageContainerLocationClient.allocateContainer(
SCMTestUtils.getReplicationType(conf),
HddsProtos.ReplicationFactor.ONE, OzoneConsts.OZONE);
- XceiverClientManager xceiverClientManager = new XceiverClientManager(conf);
- XceiverClientSpi client = xceiverClientManager
- .acquireClient(container.getPipeline());
- ContainerProtocolCalls.createContainer(client,
- container.getContainerInfo().getContainerID(), null);
+ try (XceiverClientFactory factory = new XceiverClientCreator(conf);
+ XceiverClientSpi client = factory.acquireClient(container.getPipeline())) {
+ ContainerProtocolCalls.createContainer(client,
+ container.getContainerInfo().getContainerID(), null);
+ }
}
static void shutdownCluster() {
diff --git a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/freon/TestHadoopDirTreeGenerator.java b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/freon/TestHadoopDirTreeGenerator.java
index 3140681d3dc..9137eca6c0e 100644
--- a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/freon/TestHadoopDirTreeGenerator.java
+++ b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/freon/TestHadoopDirTreeGenerator.java
@@ -152,10 +152,10 @@ private void verifyDirTree(String volumeName, String bucketName, int depth,
Path rootDir = new Path(rootPath.concat("/"));
// verify root path details
FileStatus[] fileStatuses = fileSystem.listStatus(rootDir);
+ // verify the num of peer directories, expected span count is 1
+ // as it has only one dir at root.
+ verifyActualSpan(1, fileStatuses);
for (FileStatus fileStatus : fileStatuses) {
- // verify the num of peer directories, expected span count is 1
- // as it has only one dir at root.
- verifyActualSpan(1, fileStatuses);
int actualDepth =
traverseToLeaf(fileSystem, fileStatus.getPath(), 1, depth, span,
fileCount, StorageSize.parse(perFileSize, StorageUnit.BYTES));
diff --git a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/om/TestAddRemoveOzoneManager.java b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/om/TestAddRemoveOzoneManager.java
index dfc3045be8f..c7cc83c61c4 100644
--- a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/om/TestAddRemoveOzoneManager.java
+++ b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/om/TestAddRemoveOzoneManager.java
@@ -47,6 +47,7 @@
import org.apache.hadoop.security.UserGroupInformation;
import org.apache.hadoop.util.StringUtils;
import org.apache.ozone.test.GenericTestUtils;
+import org.apache.ozone.test.tag.Flaky;
import org.apache.ratis.grpc.server.GrpcLogAppender;
import org.apache.ratis.protocol.RaftPeer;
import org.apache.ratis.protocol.RaftPeerId;
@@ -285,6 +286,7 @@ public void testBootstrapWithoutConfigUpdate() throws Exception {
* 1. Stop 1 OM and update configs on rest, bootstrap new node -> fail
* 2. Force bootstrap (with 1 node down and updated configs on rest) -> pass
*/
+ @Flaky("HDDS-11358")
@Test
public void testForceBootstrap() throws Exception {
GenericTestUtils.setLogLevel(GrpcLogAppender.LOG, Level.ERROR);
diff --git a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/om/TestOmContainerLocationCache.java b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/om/TestOmContainerLocationCache.java
index e773bf7ed7f..f25bb47f0db 100644
--- a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/om/TestOmContainerLocationCache.java
+++ b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/om/TestOmContainerLocationCache.java
@@ -18,10 +18,12 @@
package org.apache.hadoop.ozone.om;
+import com.google.common.collect.ImmutableMap;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.hadoop.hdds.HddsConfigKeys;
import org.apache.hadoop.hdds.client.ContainerBlockID;
+import org.apache.hadoop.hdds.client.ECReplicationConfig;
import org.apache.hadoop.hdds.client.RatisReplicationConfig;
import org.apache.hadoop.hdds.client.ReplicationConfig;
import org.apache.hadoop.hdds.conf.OzoneConfiguration;
@@ -89,8 +91,11 @@
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
+import java.util.ArrayList;
import java.util.Collections;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
@@ -145,10 +150,17 @@ public class TestOmContainerLocationCache {
private static ObjectStore objectStore;
private static XceiverClientGrpc mockDn1Protocol;
private static XceiverClientGrpc mockDn2Protocol;
+ private static XceiverClientGrpc mockDnEcProtocol;
private static final DatanodeDetails DN1 =
MockDatanodeDetails.createDatanodeDetails(UUID.randomUUID());
private static final DatanodeDetails DN2 =
MockDatanodeDetails.createDatanodeDetails(UUID.randomUUID());
+ private static final DatanodeDetails DN3 =
+ MockDatanodeDetails.createDatanodeDetails(UUID.randomUUID());
+ private static final DatanodeDetails DN4 =
+ MockDatanodeDetails.createDatanodeDetails(UUID.randomUUID());
+ private static final DatanodeDetails DN5 =
+ MockDatanodeDetails.createDatanodeDetails(UUID.randomUUID());
private static final AtomicLong CONTAINER_ID = new AtomicLong(1);
@@ -200,6 +212,8 @@ private static XceiverClientManager mockDataNodeClientFactory()
throws IOException {
mockDn1Protocol = spy(new XceiverClientGrpc(createPipeline(DN1), conf));
mockDn2Protocol = spy(new XceiverClientGrpc(createPipeline(DN2), conf));
+ mockDnEcProtocol = spy(new XceiverClientGrpc(createEcPipeline(
+ ImmutableMap.of(DN1, 1, DN2, 2, DN3, 3, DN4, 4, DN5, 5)), conf));
XceiverClientManager manager = mock(XceiverClientManager.class);
when(manager.acquireClient(argThat(matchEmptyPipeline())))
.thenCallRealMethod();
@@ -217,6 +231,11 @@ private static XceiverClientManager mockDataNodeClientFactory()
.thenReturn(mockDn2Protocol);
when(manager.acquireClientForReadData(argThat(matchPipeline(DN2))))
.thenReturn(mockDn2Protocol);
+
+ when(manager.acquireClient(argThat(matchEcPipeline())))
+ .thenReturn(mockDnEcProtocol);
+ when(manager.acquireClientForReadData(argThat(matchEcPipeline())))
+ .thenReturn(mockDnEcProtocol);
return manager;
}
@@ -231,6 +250,11 @@ private static ArgumentMatcher matchPipeline(DatanodeDetails dn) {
&& argument.getNodes().get(0).getUuid().equals(dn.getUuid());
}
+ private static ArgumentMatcher matchEcPipeline() {
+ return argument -> argument != null && !argument.getNodes().isEmpty()
+ && argument.getReplicationConfig() instanceof ECReplicationConfig;
+ }
+
private static void createBucket(String volumeName, String bucketName,
boolean isVersionEnabled)
throws IOException {
@@ -256,12 +280,14 @@ private static void createVolume(String volumeName) throws IOException {
public void beforeEach() throws IOException {
CONTAINER_ID.getAndIncrement();
reset(mockScmBlockLocationProtocol, mockScmContainerClient,
- mockDn1Protocol, mockDn2Protocol);
+ mockDn1Protocol, mockDn2Protocol, mockDnEcProtocol);
InnerNode.Factory factory = InnerNodeImpl.FACTORY;
when(mockScmBlockLocationProtocol.getNetworkTopology()).thenReturn(
factory.newInnerNode("", "", null, NetConstants.ROOT_LEVEL, 1));
when(mockDn1Protocol.getPipeline()).thenReturn(createPipeline(DN1));
when(mockDn2Protocol.getPipeline()).thenReturn(createPipeline(DN2));
+ when(mockDnEcProtocol.getPipeline()).thenReturn(createEcPipeline(
+ ImmutableMap.of(DN1, 1, DN2, 2, DN3, 3, DN4, 4, DN5, 5)));
}
/**
@@ -575,6 +601,48 @@ public void containerRefreshedOnEmptyPipelines() throws Exception {
.getContainerWithPipelineBatch(newHashSet(CONTAINER_ID.get()));
}
+ @Test
+ public void containerRefreshedOnInsufficientEcPipelines() throws Exception {
+ int chunkSize = 1024 * 1024;
+ int dataBlocks = 3;
+ int parityBlocks = 2;
+ int inputSize = chunkSize * dataBlocks;
+ byte[][] inputChunks = new byte[dataBlocks][chunkSize];
+
+ mockScmAllocationEcPipeline(CONTAINER_ID.get(), 1L);
+ mockWriteChunkResponse(mockDnEcProtocol);
+ mockPutBlockResponse(mockDnEcProtocol, CONTAINER_ID.get(), 1L, null);
+
+ OzoneBucket bucket = objectStore.getVolume(VOLUME_NAME).getBucket(BUCKET_NAME);
+
+ String keyName = "ecKey";
+ try (OzoneOutputStream os = bucket.createKey(keyName, inputSize,
+ new ECReplicationConfig(dataBlocks, parityBlocks, ECReplicationConfig.EcCodec.RS,
+ chunkSize), new HashMap<>())) {
+ for (int i = 0; i < dataBlocks; i++) {
+ os.write(inputChunks[i]);
+ }
+ }
+
+ // case1: pipeline replicaIndexes missing some data indexes, should not cache
+ mockScmGetContainerEcPipeline(CONTAINER_ID.get(), ImmutableMap.of(DN1, 1, DN2, 2, DN4, 4));
+ bucket.getKey(keyName);
+ verify(mockScmContainerClient, times(1))
+ .getContainerWithPipelineBatch(newHashSet(CONTAINER_ID.get()));
+ bucket.getKey(keyName);
+ verify(mockScmContainerClient, times(2))
+ .getContainerWithPipelineBatch(newHashSet(CONTAINER_ID.get()));
+
+ // case2: pipeline replicaIndexes contain all data indexes, should cache
+ mockScmGetContainerEcPipeline(CONTAINER_ID.get(), ImmutableMap.of(DN1, 1, DN2, 2, DN3, 3, DN4, 4));
+ bucket.getKey(keyName);
+ verify(mockScmContainerClient, times(3))
+ .getContainerWithPipelineBatch(newHashSet(CONTAINER_ID.get()));
+ bucket.getKey(keyName);
+ verify(mockScmContainerClient, times(3))
+ .getContainerWithPipelineBatch(newHashSet(CONTAINER_ID.get()));
+ }
+
private void mockPutBlockResponse(XceiverClientSpi mockDnProtocol,
long containerId, long localId,
byte[] data)
@@ -661,6 +729,22 @@ private void mockScmAllocationOnDn1(long containerID,
.thenReturn(Collections.singletonList(block));
}
+ private void mockScmAllocationEcPipeline(long containerID, long localId)
+ throws IOException {
+ ContainerBlockID blockId = new ContainerBlockID(containerID, localId);
+ AllocatedBlock block = new AllocatedBlock.Builder()
+ .setPipeline(createEcPipeline(ImmutableMap.of(DN1, 1, DN2, 2, DN3, 3, DN4, 4, DN5, 5)))
+ .setContainerBlockID(blockId)
+ .build();
+ when(mockScmBlockLocationProtocol
+ .allocateBlock(anyLong(), anyInt(),
+ any(ECReplicationConfig.class),
+ anyString(),
+ any(ExcludeList.class),
+ anyString()))
+ .thenReturn(Collections.singletonList(block));
+ }
+
private void mockScmGetContainerPipeline(long containerId,
DatanodeDetails dn)
throws IOException {
@@ -690,6 +774,20 @@ private void mockScmGetContainerPipelineEmpty(long containerId)
newHashSet(containerId))).thenReturn(containerWithPipelines);
}
+ private void mockScmGetContainerEcPipeline(long containerId, Map indexes)
+ throws IOException {
+ Pipeline pipeline = createEcPipeline(indexes);
+ ContainerInfo containerInfo = new ContainerInfo.Builder()
+ .setContainerID(containerId)
+ .setPipelineID(pipeline.getId()).build();
+ List containerWithPipelines =
+ Collections.singletonList(
+ new ContainerWithPipeline(containerInfo, pipeline));
+
+ when(mockScmContainerClient.getContainerWithPipelineBatch(
+ newHashSet(containerId))).thenReturn(containerWithPipelines);
+ }
+
private void mockGetBlock(XceiverClientGrpc mockDnProtocol,
long containerId, long localId,
byte[] data,
@@ -788,4 +886,14 @@ private static Pipeline createPipeline(List nodes) {
.setNodes(nodes)
.build();
}
+
+ private static Pipeline createEcPipeline(Map indexes) {
+ return Pipeline.newBuilder()
+ .setState(Pipeline.PipelineState.OPEN)
+ .setId(PipelineID.randomId())
+ .setReplicationConfig(new ECReplicationConfig(3, 2))
+ .setReplicaIndexes(indexes)
+ .setNodes(new ArrayList<>(indexes.keySet()))
+ .build();
+ }
}
diff --git a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/om/TestOzoneManagerHAWithStoppedNodes.java b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/om/TestOzoneManagerHAWithStoppedNodes.java
index 2d34f5fc403..6937c52c712 100644
--- a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/om/TestOzoneManagerHAWithStoppedNodes.java
+++ b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/om/TestOzoneManagerHAWithStoppedNodes.java
@@ -42,6 +42,7 @@
import org.apache.hadoop.security.UserGroupInformation;
import org.apache.log4j.Logger;
import org.apache.ozone.test.GenericTestUtils;
+import org.apache.ozone.test.tag.Flaky;
import org.apache.ratis.conf.RaftProperties;
import org.apache.ratis.server.RaftServerConfigKeys;
import org.apache.ratis.util.TimeDuration;
@@ -76,6 +77,7 @@
* Ozone Manager HA tests that stop/restart one or more OM nodes.
* @see TestOzoneManagerHAWithAllRunning
*/
+@Flaky("HDDS-11352")
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class TestOzoneManagerHAWithStoppedNodes extends TestOzoneManagerHA {
@@ -484,6 +486,8 @@ void testIncrementalWaitTimeWithSameNodeFailover() throws Exception {
assertEquals((numTimesTriedToSameNode + 1) * waitBetweenRetries,
omFailoverProxyProvider.getWaitTime());
}
+
+ @Flaky("HDDS-11353")
@Test
void testOMHAMetrics() throws Exception {
// Get leader OM
diff --git a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/om/snapshot/TestOzoneManagerSnapshotAcl.java b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/om/snapshot/TestOzoneManagerSnapshotAcl.java
index 5694edd773e..96099498438 100644
--- a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/om/snapshot/TestOzoneManagerSnapshotAcl.java
+++ b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/om/snapshot/TestOzoneManagerSnapshotAcl.java
@@ -48,6 +48,7 @@
import org.apache.hadoop.ozone.security.acl.OzoneObj;
import org.apache.hadoop.ozone.security.acl.OzoneObjInfo;
import org.apache.hadoop.security.UserGroupInformation;
+import org.apache.ozone.test.tag.Flaky;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Timeout;
@@ -402,6 +403,7 @@ public void testLookupKeyWithAllowedUserForPrefixAcl(BucketLayout bucketLayout)
assertDoesNotThrow(() -> ozoneManager.lookupKey(snapshotKeyArgs));
}
+ @Flaky("HDDS-11354")
@ParameterizedTest
@EnumSource(BucketLayout.class)
public void testLookupKeyWithNotAllowedUserForPrefixAcl(BucketLayout bucketLayout) throws Exception {
diff --git a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/shell/TestOzoneShellHA.java b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/shell/TestOzoneShellHA.java
index 5a46d571c6b..89f068cdedf 100644
--- a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/shell/TestOzoneShellHA.java
+++ b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/shell/TestOzoneShellHA.java
@@ -1568,6 +1568,39 @@ public void testShQuota() throws Exception {
.contains("Missing required parameter");
out.reset();
+ // Test incompatible volume-bucket quota
+ args = new String[]{"volume", "create", "vol6"};
+ execute(ozoneShell, args);
+ out.reset();
+
+ args = new String[]{"bucket", "create", "vol6/buck6"};
+ execute(ozoneShell, args);
+ out.reset();
+
+ args = new String[]{"volume", "setquota", "vol6", "--space-quota", "1000B"};
+ executeWithError(ozoneShell, args, "Can not set volume space quota " +
+ "on volume as some of buckets in this volume have no quota set");
+ out.reset();
+
+ args = new String[]{"bucket", "setquota", "vol6/buck6", "--space-quota", "1000B"};
+ execute(ozoneShell, args);
+ out.reset();
+
+ args = new String[]{"volume", "setquota", "vol6", "--space-quota", "2000B"};
+ execute(ozoneShell, args);
+ out.reset();
+
+ args = new String[]{"bucket", "create", "vol6/buck62"};
+ executeWithError(ozoneShell, args, "Bucket space quota in this " +
+ "volume should be set as volume space quota is already set.");
+ out.reset();
+
+ args = new String[]{"bucket", "create", "vol6/buck62", "--space-quota", "2000B"};
+ executeWithError(ozoneShell, args, "Total buckets quota in this volume " +
+ "should not be greater than volume quota : the total space quota is set to:3000. " +
+ "But the volume space quota is:2000");
+ out.reset();
+
// Test set bucket spaceQuota or nameSpaceQuota to normal value.
String[] bucketArgs8 = new String[]{"bucket", "setquota", "vol4/buck4",
"--space-quota", "1000B"};
diff --git a/hadoop-ozone/interface-client/pom.xml b/hadoop-ozone/interface-client/pom.xml
index c196dca045d..18d9584fbc8 100644
--- a/hadoop-ozone/interface-client/pom.xml
+++ b/hadoop-ozone/interface-client/pom.xml
@@ -33,6 +33,10 @@ https://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+ com.google.guava
+ guava
+
com.google.protobuf
protobuf-java
@@ -41,6 +45,22 @@ https://maven.apache.org/xsd/maven-4.0.0.xsd">
org.apache.ozone
hdds-interface-client
+
+
+ org.apache.hadoop.thirdparty
+ hadoop-shaded-protobuf_3_7
+
+
+
+ io.grpc
+ grpc-api
+
+
+ com.google.code.findbugs
+ jsr305
+
+
+
io.grpc
grpc-protobuf
diff --git a/hadoop-ozone/interface-client/src/main/proto/OmClientProtocol.proto b/hadoop-ozone/interface-client/src/main/proto/OmClientProtocol.proto
index 32bba266080..9e0f729be40 100644
--- a/hadoop-ozone/interface-client/src/main/proto/OmClientProtocol.proto
+++ b/hadoop-ozone/interface-client/src/main/proto/OmClientProtocol.proto
@@ -147,8 +147,9 @@ enum Type {
ListStatusLight = 129;
GetSnapshotInfo = 130;
RenameSnapshot = 131;
-
ListOpenFiles = 132;
+ QuotaRepair = 133;
+ GetServerDefaults = 134;
}
enum SafeMode {
@@ -285,8 +286,9 @@ message OMRequest {
optional SetSnapshotPropertyRequest SetSnapshotPropertyRequest = 127;
optional SnapshotInfoRequest SnapshotInfoRequest = 128;
optional RenameSnapshotRequest RenameSnapshotRequest = 129;
-
optional ListOpenFilesRequest ListOpenFilesRequest = 130;
+ optional QuotaRepairRequest QuotaRepairRequest = 131;
+ optional ServerDefaultsRequest ServerDefaultsRequest = 132;
}
message OMResponse {
@@ -410,8 +412,9 @@ message OMResponse {
optional SnapshotInfoResponse SnapshotInfoResponse = 130;
optional OMLockDetailsProto omLockDetails = 131;
optional RenameSnapshotResponse RenameSnapshotResponse = 132;
-
optional ListOpenFilesResponse ListOpenFilesResponse = 133;
+ optional QuotaRepairResponse QuotaRepairResponse = 134;
+ optional ServerDefaultsResponse ServerDefaultsResponse = 135;
}
enum Status {
@@ -2187,6 +2190,32 @@ message SetSafeModeResponse {
optional bool response = 1;
}
+message QuotaRepairRequest {
+ repeated BucketQuotaCount bucketCount = 1;
+ required bool supportVolumeOldQuota = 2 [default=false];
+}
+message BucketQuotaCount {
+ required string volName = 1;
+ required string bucketName = 2;
+ required int64 diffUsedBytes = 3;
+ required int64 diffUsedNamespace = 4;
+ required bool supportOldQuota = 5 [default=false];
+}
+
+message QuotaRepairResponse {
+}
+
+message ServerDefaultsRequest {
+}
+
+message FsServerDefaultsProto {
+ optional string keyProviderUri = 1;
+}
+
+message ServerDefaultsResponse {
+ required FsServerDefaultsProto serverDefaults = 1;
+}
+
message OMLockDetailsProto {
optional bool isLockAcquired = 1;
optional uint64 waitLockNanos = 2;
diff --git a/hadoop-ozone/interface-storage/pom.xml b/hadoop-ozone/interface-storage/pom.xml
index ca7f14f1fa5..ab1cc275ac1 100644
--- a/hadoop-ozone/interface-storage/pom.xml
+++ b/hadoop-ozone/interface-storage/pom.xml
@@ -31,11 +31,32 @@
+
+ org.apache.ozone
+ hdds-common
+
+
+ org.apache.ozone
+ hdds-interface-client
+
org.apache.ozone
ozone-common
+
+ org.apache.ozone
+ rocksdb-checkpoint-differ
+
+
+ org.apache.ratis
+ ratis-common
+
+
+
+ com.google.guava
+ guava
+
com.google.protobuf
protobuf-java
diff --git a/hadoop-ozone/ozone-manager/pom.xml b/hadoop-ozone/ozone-manager/pom.xml
index 5f6bc54c5af..ae427727def 100644
--- a/hadoop-ozone/ozone-manager/pom.xml
+++ b/hadoop-ozone/ozone-manager/pom.xml
@@ -32,6 +32,35 @@ https://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+ org.apache.ozone
+ hdds-annotation-processing
+ test
+
+
+ org.apache.ozone
+ hdds-client
+
+
+ org.apache.ozone
+ hdds-common
+
+
+ org.apache.ozone
+ hdds-config
+
+
+ org.apache.ozone
+ hdds-interface-server
+
+
+ org.apache.ozone
+ hdds-managed-rocksdb
+
+
+ org.apache.ozone
+ ozone-interface-client
+
org.aspectj
@@ -85,25 +114,132 @@ https://maven.apache.org/xsd/maven-4.0.0.xsd">
rocksdb-checkpoint-differ
+
+ org.apache.commons
+ commons-compress
+
+
+ org.apache.commons
+ commons-lang3
+
+
+ org.apache.kerby
+ kerby-util
+
+
+ org.apache.logging.log4j
+ log4j-api
+
+
+ org.apache.ratis
+ ratis-common
+
+
+ org.apache.ratis
+ ratis-grpc
+
+
+ org.apache.ratis
+ ratis-netty
+
+
+ org.apache.ratis
+ ratis-proto
+
+
+ org.apache.ratis
+ ratis-server-api
+
+
+ org.apache.ratis
+ ratis-server
+
+
+ org.apache.ratis
+ ratis-thirdparty-misc
+
+
org.bouncycastle
bcprov-jdk18on
+
+ io.grpc
+ grpc-api
+
+
+ com.google.code.findbugs
+ jsr305
+
+
+
+
+ io.grpc
+ grpc-netty
+
+
+ io.grpc
+ grpc-stub
+
+
+ io.netty
+ netty-common
+
+
+ io.netty
+ netty-handler
+
io.netty
netty-tcnative-boringssl-static
runtime
+
+ io.netty
+ netty-transport
+
org.reflections
reflections
+
+ com.fasterxml.jackson.core
+ jackson-annotations
+
+
+ com.fasterxml.jackson.core
+ jackson-databind
+
+
+ com.google.guava
+ guava
+
+
+ com.google.protobuf
+ protobuf-java
+
com.sun.jersey
jersey-client
+
+ info.picocli
+ picocli
+
+
+ jakarta.annotation
+ jakarta.annotation-api
+
+
+ jakarta.xml.bind
+ jakarta.xml.bind-api
+
+
+ javax.servlet
+ javax.servlet-api
+
@@ -134,7 +270,7 @@ https://maven.apache.org/xsd/maven-4.0.0.xsd">
org.apache.ranger
- ranger-intg
+ ranger-plugins-common
${ranger.version}
compile
diff --git a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/audit/OMSystemAction.java b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/audit/OMSystemAction.java
new file mode 100644
index 00000000000..9f5b6ccebcf
--- /dev/null
+++ b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/audit/OMSystemAction.java
@@ -0,0 +1,31 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with this
+ * work for additional information regarding copyright ownership. The ASF
+ * licenses this file to you 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 org.apache.hadoop.ozone.audit;
+
+/**
+ * Enum to define Audit Action types for system audit in OzoneManager. This will in addition to OMAction
+ * as present for request.
+ */
+public enum OMSystemAction implements AuditAction {
+ STARTUP;
+
+ @Override
+ public String getAction() {
+ return this.toString();
+ }
+}
diff --git a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OzoneManager.java b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OzoneManager.java
index 03896a042ec..a514262cae2 100644
--- a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OzoneManager.java
+++ b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OzoneManager.java
@@ -26,6 +26,7 @@
import java.io.UncheckedIOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
+import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
@@ -90,7 +91,9 @@
import org.apache.hadoop.hdds.utils.db.Table;
import org.apache.hadoop.hdds.utils.db.Table.KeyValue;
import org.apache.hadoop.hdds.utils.db.TableIterator;
+import org.apache.hadoop.ozone.OzoneFsServerDefaults;
import org.apache.hadoop.ozone.OzoneManagerVersion;
+import org.apache.hadoop.ozone.audit.OMSystemAction;
import org.apache.hadoop.ozone.om.helpers.LeaseKeyInfo;
import org.apache.hadoop.ozone.om.helpers.ListOpenFilesResult;
import org.apache.hadoop.ozone.om.helpers.SnapshotDiffJob;
@@ -186,6 +189,7 @@
import org.apache.hadoop.ozone.om.protocolPB.OMAdminProtocolPB;
import org.apache.hadoop.ozone.om.protocolPB.OzoneManagerProtocolPB;
import org.apache.hadoop.hdds.security.exception.OzoneSecurityException;
+import org.apache.hadoop.hdds.utils.LegacyHadoopConfigurationSource;
import org.apache.hadoop.hdds.utils.TransactionInfo;
import org.apache.hadoop.ozone.om.ratis.OzoneManagerRatisServer;
import org.apache.hadoop.ozone.om.ratis.utils.OzoneManagerRatisUtils;
@@ -351,6 +355,9 @@ public final class OzoneManager extends ServiceRuntimeInfoImpl
private static final AuditLogger AUDIT = new AuditLogger(
AuditLoggerType.OMLOGGER);
+ private static final AuditLogger SYSTEMAUDIT = new AuditLogger(
+ AuditLoggerType.OMSYSTEMLOGGER);
+
private static final String OM_DAEMON = "om";
// This is set for read requests when OMRequest has S3Authentication set,
@@ -430,6 +437,7 @@ public final class OzoneManager extends ServiceRuntimeInfoImpl
private List ratisReporterList = null;
private KeyProviderCryptoExtension kmsProvider;
+ private OzoneFsServerDefaults serverDefaults;
private final OMLayoutVersionManager versionManager;
private final ReplicationConfigValidator replicationConfigValidator;
@@ -647,6 +655,14 @@ private OzoneManager(OzoneConfiguration conf, StartupOption startupOption)
kmsProvider = null;
LOG.error("Fail to create Key Provider");
}
+ Configuration hadoopConfig =
+ LegacyHadoopConfigurationSource.asHadoopConfiguration(configuration);
+ URI keyProviderUri = KMSUtil.getKeyProviderUri(
+ hadoopConfig,
+ CommonConfigurationKeysPublic.HADOOP_SECURITY_KEY_PROVIDER_PATH);
+ String keyProviderUriStr =
+ (keyProviderUri != null) ? keyProviderUri.toString() : null;
+ serverDefaults = new OzoneFsServerDefaults(keyProviderUriStr);
if (secConfig.isSecurityEnabled()) {
omComponent = OM_DAEMON + "-" + omId;
HddsProtos.OzoneManagerDetailsProto omInfo =
@@ -1644,11 +1660,15 @@ public OMPerformanceMetrics getPerfMetrics() {
* Start service.
*/
public void start() throws IOException {
+ Map auditMap = new HashMap();
+ auditMap.put("OmState", omState.name());
if (omState == State.BOOTSTRAPPING) {
if (isBootstrapping) {
+ auditMap.put("Bootstrap", "normal");
// Check that all OM configs have been updated with the new OM info.
checkConfigBeforeBootstrap();
} else if (isForcedBootstrapping) {
+ auditMap.put("Bootstrap", "force");
LOG.warn("Skipped checking whether existing OM configs have been " +
"updated with this OM information as force bootstrap is called.");
}
@@ -1736,12 +1756,17 @@ public void start() throws IOException {
}
omState = State.RUNNING;
+ auditMap.put("NewOmState", omState.name());
+ SYSTEMAUDIT.logWriteSuccess(buildAuditMessageForSuccess(OMSystemAction.STARTUP, auditMap));
}
/**
* Restarts the service. This method re-initializes the rpc server.
*/
public void restart() throws IOException {
+ Map auditMap = new HashMap();
+ auditMap.put("OmState", omState.name());
+ auditMap.put("Trigger", "restart");
setInstanceVariablesFromConf();
LOG.info(buildRpcServerStartMessage("OzoneManager RPC server",
@@ -1808,6 +1833,8 @@ public void restart() throws IOException {
startJVMPauseMonitor();
setStartTime();
omState = State.RUNNING;
+ auditMap.put("NewOmState", omState.name());
+ SYSTEMAUDIT.logWriteSuccess(buildAuditMessageForSuccess(OMSystemAction.STARTUP, auditMap));
}
/**
@@ -3037,6 +3064,10 @@ public AuditLogger getAuditLogger() {
return AUDIT;
}
+ public AuditLogger getSystemAuditLogger() {
+ return SYSTEMAUDIT;
+ }
+
@Override
public AuditMessage buildAuditMessageForSuccess(AuditAction op,
Map auditMap) {
@@ -4749,6 +4780,11 @@ public boolean setSafeMode(SafeModeAction action, boolean isChecked)
}
}
+ @Override
+ public OzoneFsServerDefaults getServerDefaults() {
+ return serverDefaults;
+ }
+
/**
* Write down Layout version of a finalized feature to DB on finalization.
* @param lvm OMLayoutVersionManager
diff --git a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/ScmClient.java b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/ScmClient.java
index 77ed7f63ad5..318decfa70f 100644
--- a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/ScmClient.java
+++ b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/ScmClient.java
@@ -21,6 +21,8 @@
import com.google.common.cache.CacheLoader;
import com.google.common.cache.CacheLoader.InvalidCacheLoadException;
import com.google.common.cache.LoadingCache;
+import org.apache.hadoop.hdds.client.ECReplicationConfig;
+import org.apache.hadoop.hdds.client.ReplicationConfig;
import org.apache.hadoop.hdds.conf.OzoneConfiguration;
import org.apache.hadoop.hdds.scm.container.common.helpers.ContainerWithPipeline;
import org.apache.hadoop.hdds.scm.pipeline.Pipeline;
@@ -113,12 +115,29 @@ public Map getContainerLocations(Iterable containerIds,
}
try {
Map result = containerLocationCache.getAll(containerIds);
- // Don't keep empty pipelines in the cache.
- List emptyPipelines = result.entrySet().stream()
- .filter(e -> e.getValue().isEmpty())
+ // Don't keep empty pipelines or insufficient EC pipelines in the cache.
+ List uncachePipelines = result.entrySet().stream()
+ .filter(e -> {
+ Pipeline pipeline = e.getValue();
+ // filter empty pipelines
+ if (pipeline.isEmpty()) {
+ return true;
+ }
+ // filter insufficient EC pipelines which missing any data index
+ ReplicationConfig repConfig = pipeline.getReplicationConfig();
+ if (repConfig instanceof ECReplicationConfig) {
+ int d = ((ECReplicationConfig) repConfig).getData();
+ for (int i = 1; i <= d; i++) {
+ if (!pipeline.getReplicaIndexes().containsValue(i)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ })
.map(Map.Entry::getKey)
.collect(Collectors.toList());
- containerLocationCache.invalidateAll(emptyPipelines);
+ containerLocationCache.invalidateAll(uncachePipelines);
return result;
} catch (ExecutionException e) {
return handleCacheExecutionException(e);
diff --git a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/ratis/OzoneManagerRatisServer.java b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/ratis/OzoneManagerRatisServer.java
index aa9612ef805..78d6ed89d2d 100644
--- a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/ratis/OzoneManagerRatisServer.java
+++ b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/ratis/OzoneManagerRatisServer.java
@@ -44,6 +44,7 @@
import org.apache.hadoop.hdds.HddsUtils;
import org.apache.hadoop.hdds.conf.ConfigurationSource;
+import org.apache.hadoop.hdds.conf.RatisConfUtils;
import org.apache.hadoop.hdds.conf.StorageUnit;
import org.apache.hadoop.hdds.ratis.RatisHelper;
import org.apache.hadoop.hdds.security.SecurityConfig;
@@ -624,17 +625,16 @@ public static RaftProperties newRaftProperties(ConfigurationSource conf,
// Set Ratis storage directory
RaftServerConfigKeys.setStorageDir(properties, Collections.singletonList(new File(ratisStorageDir)));
- final int logAppenderQueueByteLimit = (int) conf.getStorageSize(
+ final int logAppenderBufferByteLimit = (int) conf.getStorageSize(
OMConfigKeys.OZONE_OM_RATIS_LOG_APPENDER_QUEUE_BYTE_LIMIT,
OMConfigKeys.OZONE_OM_RATIS_LOG_APPENDER_QUEUE_BYTE_LIMIT_DEFAULT, StorageUnit.BYTES);
+ setRaftLogProperties(properties, logAppenderBufferByteLimit, conf);
// For grpc config
- setGrpcConfig(properties, logAppenderQueueByteLimit);
+ RatisConfUtils.Grpc.setMessageSizeMax(properties, logAppenderBufferByteLimit);
setRaftLeaderElectionProperties(properties, conf);
- setRaftLogProperties(properties, logAppenderQueueByteLimit, conf);
-
setRaftRpcProperties(properties, conf);
setRaftRetryCacheProperties(properties, conf);
@@ -693,12 +693,6 @@ private static void setRaftLogProperties(RaftProperties properties,
RaftServerConfigKeys.Log.setSegmentCacheNumMax(properties, 2);
}
- private static void setGrpcConfig(RaftProperties properties, int logAppenderQueueByteLimit) {
- // For grpc set the maximum message size
- // TODO: calculate the optimal max message size
- GrpcConfigKeys.setMessageSizeMax(properties, SizeInBytes.valueOf(logAppenderQueueByteLimit));
- }
-
private static void setRaftRpcProperties(RaftProperties properties, ConfigurationSource conf) {
// Set the server request timeout
TimeUnit serverRequestTimeoutUnit = OMConfigKeys.OZONE_OM_RATIS_SERVER_REQUEST_TIMEOUT_DEFAULT.getUnit();
diff --git a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/ratis/utils/OzoneManagerRatisUtils.java b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/ratis/utils/OzoneManagerRatisUtils.java
index 8ff59e091d8..5dc640c742c 100644
--- a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/ratis/utils/OzoneManagerRatisUtils.java
+++ b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/ratis/utils/OzoneManagerRatisUtils.java
@@ -84,6 +84,7 @@
import org.apache.hadoop.ozone.om.request.upgrade.OMFinalizeUpgradeRequest;
import org.apache.hadoop.ozone.om.request.upgrade.OMPrepareRequest;
import org.apache.hadoop.ozone.om.request.util.OMEchoRPCWriteRequest;
+import org.apache.hadoop.ozone.om.request.volume.OMQuotaRepairRequest;
import org.apache.hadoop.ozone.om.request.volume.OMVolumeCreateRequest;
import org.apache.hadoop.ozone.om.request.volume.OMVolumeDeleteRequest;
import org.apache.hadoop.ozone.om.request.volume.OMVolumeSetOwnerRequest;
@@ -331,6 +332,8 @@ public static OMClientRequest createClientRequest(OMRequest omRequest,
return new OMEchoRPCWriteRequest(omRequest);
case AbortExpiredMultiPartUploads:
return new S3ExpiredMultipartUploadsAbortRequest(omRequest);
+ case QuotaRepair:
+ return new OMQuotaRepairRequest(omRequest);
default:
throw new OMException("Unrecognized write command type request "
+ cmdType, OMException.ResultCodes.INVALID_REQUEST);
diff --git a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/snapshot/OMSnapshotPurgeRequest.java b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/snapshot/OMSnapshotPurgeRequest.java
index 29c7628e3cc..2a9cfa6baf0 100644
--- a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/snapshot/OMSnapshotPurgeRequest.java
+++ b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/snapshot/OMSnapshotPurgeRequest.java
@@ -19,10 +19,7 @@
package org.apache.hadoop.ozone.om.request.snapshot;
-import org.apache.commons.lang3.tuple.Triple;
-import org.apache.hadoop.ozone.om.OMMetadataManager;
import org.apache.hadoop.ozone.om.OMMetrics;
-import org.apache.hadoop.ozone.om.exceptions.OMException;
import org.apache.ratis.server.protocol.TermIndex;
import org.apache.hadoop.hdds.utils.db.cache.CacheKey;
import org.apache.hadoop.hdds.utils.db.cache.CacheValue;
@@ -44,15 +41,11 @@
import java.io.IOException;
import java.util.HashMap;
-import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
-import java.util.Set;
import java.util.UUID;
-import static org.apache.hadoop.ozone.om.lock.OzoneManagerLock.Resource.SNAPSHOT_LOCK;
-
/**
* Handles OMSnapshotPurge Request.
* This is an OM internal request. Does not need @RequireSnapshotFeatureState.
@@ -92,62 +85,34 @@ public OMClientResponse validateAndUpdateCache(OzoneManager ozoneManager, TermIn
new HashMap<>();
// Each snapshot purge operation does three things:
- // 1. Update the snapshot chain,
- // 2. Update the deep clean flag for the next active snapshot (So that it can be
+ // 1. Update the deep clean flag for the next active snapshot (So that it can be
// deep cleaned by the KeyDeletingService in the next run),
+ // 2. Update the snapshot chain,
// 3. Finally, purge the snapshot.
- // All of these steps have to be performed only when it acquires all the necessary
- // locks (lock on the snapshot to be purged, lock on the next active snapshot, and
- // lock on the next path and global previous snapshots). Ideally, there is no need
- // for locks for snapshot purge and can rely on OMStateMachine because OMStateMachine
- // is going to process each request sequentially.
- //
- // But there is a problem with that. After filtering unnecessary SST files for a snapshot,
- // SstFilteringService updates that snapshot's SstFilter flag. SstFilteringService cannot
- // use SetSnapshotProperty API because it runs on each OM independently and One OM does
- // not know if the snapshot has been filtered on the other OM in HA environment.
- //
- // If locks are not taken snapshot purge and SstFilteringService will cause a race condition
- // and override one's update with another.
+ // There is no need to take lock for snapshot purge as of now. We can simply rely on OMStateMachine
+ // because it executes transaction sequentially.
for (String snapTableKey : snapshotDbKeys) {
- // To acquire all the locks, a set is maintained which is keyed by snapshotTableKey.
- // snapshotTableKey is nothing but /volumeName/bucketName/snapshotName.
- // Once all the locks are acquired, it performs the three steps mentioned above and
- // release all the locks after that.
- Set> lockSet = new HashSet<>(4, 1);
- try {
- if (omMetadataManager.getSnapshotInfoTable().get(snapTableKey) == null) {
- // Snapshot may have been purged in the previous iteration of SnapshotDeletingService.
- LOG.warn("The snapshot {} is not longer in snapshot table, It maybe removed in the previous " +
- "Snapshot purge request.", snapTableKey);
- continue;
- }
-
- acquireLock(lockSet, snapTableKey, omMetadataManager);
- SnapshotInfo fromSnapshot = omMetadataManager.getSnapshotInfoTable().get(snapTableKey);
-
- SnapshotInfo nextSnapshot =
- SnapshotUtils.getNextActiveSnapshot(fromSnapshot, snapshotChainManager, omSnapshotManager);
-
- if (nextSnapshot != null) {
- acquireLock(lockSet, nextSnapshot.getTableKey(), omMetadataManager);
- }
-
- // Update the chain first so that it has all the necessary locks before updating deep clean.
- updateSnapshotChainAndCache(lockSet, omMetadataManager, fromSnapshot, trxnLogIndex,
- updatedPathPreviousAndGlobalSnapshots);
- updateSnapshotInfoAndCache(nextSnapshot, omMetadataManager, trxnLogIndex, updatedSnapInfos);
- // Remove and close snapshot's RocksDB instance from SnapshotCache.
- omSnapshotManager.invalidateCacheEntry(fromSnapshot.getSnapshotId());
- // Update SnapshotInfoTable cache.
- omMetadataManager.getSnapshotInfoTable()
- .addCacheEntry(new CacheKey<>(fromSnapshot.getTableKey()), CacheValue.get(trxnLogIndex));
- } finally {
- for (Triple lockKey: lockSet) {
- omMetadataManager.getLock()
- .releaseWriteLock(SNAPSHOT_LOCK, lockKey.getLeft(), lockKey.getMiddle(), lockKey.getRight());
- }
+ SnapshotInfo fromSnapshot = omMetadataManager.getSnapshotInfoTable().get(snapTableKey);
+ if (fromSnapshot == null) {
+ // Snapshot may have been purged in the previous iteration of SnapshotDeletingService.
+ LOG.warn("The snapshot {} is not longer in snapshot table, It maybe removed in the previous " +
+ "Snapshot purge request.", snapTableKey);
+ continue;
}
+
+ SnapshotInfo nextSnapshot =
+ SnapshotUtils.getNextActiveSnapshot(fromSnapshot, snapshotChainManager, omSnapshotManager);
+
+ // Step 1: Update the deep clean flag for the next active snapshot
+ updateSnapshotInfoAndCache(nextSnapshot, omMetadataManager, trxnLogIndex, updatedSnapInfos);
+ // Step 2: Update the snapshot chain.
+ updateSnapshotChainAndCache(omMetadataManager, fromSnapshot, trxnLogIndex,
+ updatedPathPreviousAndGlobalSnapshots);
+ // Remove and close snapshot's RocksDB instance from SnapshotCache.
+ omSnapshotManager.invalidateCacheEntry(fromSnapshot.getSnapshotId());
+ // Step 3: Purge the snapshot from SnapshotInfoTable cache.
+ omMetadataManager.getSnapshotInfoTable()
+ .addCacheEntry(new CacheKey<>(fromSnapshot.getTableKey()), CacheValue.get(trxnLogIndex));
}
omClientResponse = new OMSnapshotPurgeResponse(omResponse.build(),
@@ -168,41 +133,19 @@ public OMClientResponse validateAndUpdateCache(OzoneManager ozoneManager, TermIn
return omClientResponse;
}
- private void acquireLock(Set> lockSet, String snapshotTableKey,
- OMMetadataManager omMetadataManager) throws IOException {
- SnapshotInfo snapshotInfo = omMetadataManager.getSnapshotInfoTable().get(snapshotTableKey);
-
- // It should not be the case that lock is required for non-existing snapshot.
- if (snapshotInfo == null) {
- LOG.error("Snapshot: '{}' doesn't not exist in snapshot table.", snapshotTableKey);
- throw new OMException("Snapshot: '{" + snapshotTableKey + "}' doesn't not exist in snapshot table.",
- OMException.ResultCodes.FILE_NOT_FOUND);
- }
- Triple lockKey = Triple.of(snapshotInfo.getVolumeName(), snapshotInfo.getBucketName(),
- snapshotInfo.getName());
- if (!lockSet.contains(lockKey)) {
- mergeOmLockDetails(omMetadataManager.getLock()
- .acquireWriteLock(SNAPSHOT_LOCK, lockKey.getLeft(), lockKey.getMiddle(), lockKey.getRight()));
- lockSet.add(lockKey);
- }
- }
-
private void updateSnapshotInfoAndCache(SnapshotInfo snapInfo,
OmMetadataManagerImpl omMetadataManager, long trxnLogIndex,
- Map updatedSnapInfos) throws IOException {
+ Map updatedSnapInfos) throws IOException {
if (snapInfo != null) {
- // Fetch the latest value again after acquiring lock.
- SnapshotInfo updatedSnapshotInfo = omMetadataManager.getSnapshotInfoTable().get(snapInfo.getTableKey());
-
// Setting next snapshot deep clean to false, Since the
// current snapshot is deleted. We can potentially
// reclaim more keys in the next snapshot.
- updatedSnapshotInfo.setDeepClean(false);
+ snapInfo.setDeepClean(false);
// Update table cache first
- omMetadataManager.getSnapshotInfoTable().addCacheEntry(new CacheKey<>(updatedSnapshotInfo.getTableKey()),
- CacheValue.get(trxnLogIndex, updatedSnapshotInfo));
- updatedSnapInfos.put(updatedSnapshotInfo.getTableKey(), updatedSnapshotInfo);
+ omMetadataManager.getSnapshotInfoTable().addCacheEntry(new CacheKey<>(snapInfo.getTableKey()),
+ CacheValue.get(trxnLogIndex, snapInfo));
+ updatedSnapInfos.put(snapInfo.getTableKey(), snapInfo);
}
}
@@ -213,7 +156,6 @@ private void updateSnapshotInfoAndCache(SnapshotInfo snapInfo,
* update in DB.
*/
private void updateSnapshotChainAndCache(
- Set> lockSet,
OmMetadataManagerImpl metadataManager,
SnapshotInfo snapInfo,
long trxnLogIndex,
@@ -247,18 +189,12 @@ private void updateSnapshotChainAndCache(
snapInfo.getSnapshotPath(), snapInfo.getSnapshotId());
nextPathSnapshotKey = snapshotChainManager
.getTableKey(nextPathSnapshotId);
-
- // Acquire lock from the snapshot
- acquireLock(lockSet, nextPathSnapshotKey, metadataManager);
}
String nextGlobalSnapshotKey = null;
if (hasNextGlobalSnapshot) {
UUID nextGlobalSnapshotId = snapshotChainManager.nextGlobalSnapshot(snapInfo.getSnapshotId());
nextGlobalSnapshotKey = snapshotChainManager.getTableKey(nextGlobalSnapshotId);
-
- // Acquire lock from the snapshot
- acquireLock(lockSet, nextGlobalSnapshotKey, metadataManager);
}
SnapshotInfo nextPathSnapInfo =
diff --git a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/snapshot/OMSnapshotSetPropertyRequest.java b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/snapshot/OMSnapshotSetPropertyRequest.java
index c4ca3dc99e3..53047fd8026 100644
--- a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/snapshot/OMSnapshotSetPropertyRequest.java
+++ b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/snapshot/OMSnapshotSetPropertyRequest.java
@@ -38,7 +38,6 @@
import java.io.IOException;
import static org.apache.hadoop.ozone.om.exceptions.OMException.ResultCodes.FILE_NOT_FOUND;
-import static org.apache.hadoop.ozone.om.lock.OzoneManagerLock.Resource.SNAPSHOT_LOCK;
/**
* Updates the exclusive size of the snapshot.
@@ -55,7 +54,7 @@ public OMSnapshotSetPropertyRequest(OMRequest omRequest) {
public OMClientResponse validateAndUpdateCache(OzoneManager ozoneManager, TermIndex termIndex) {
OMMetrics omMetrics = ozoneManager.getMetrics();
- OMClientResponse omClientResponse = null;
+ OMClientResponse omClientResponse;
OMMetadataManager metadataManager = ozoneManager.getMetadataManager();
OzoneManagerProtocolProtos.OMResponse.Builder omResponse =
@@ -63,33 +62,16 @@ public OMClientResponse validateAndUpdateCache(OzoneManager ozoneManager, TermIn
OzoneManagerProtocolProtos.SetSnapshotPropertyRequest
setSnapshotPropertyRequest = getOmRequest()
.getSetSnapshotPropertyRequest();
- SnapshotInfo updatedSnapInfo = null;
String snapshotKey = setSnapshotPropertyRequest.getSnapshotKey();
- boolean acquiredSnapshotLock = false;
- String volumeName = null;
- String bucketName = null;
- String snapshotName = null;
try {
- SnapshotInfo snapshotInfo = metadataManager.getSnapshotInfoTable().get(snapshotKey);
- if (snapshotInfo == null) {
+ SnapshotInfo updatedSnapInfo = metadataManager.getSnapshotInfoTable().get(snapshotKey);
+ if (updatedSnapInfo == null) {
LOG.error("Snapshot: '{}' doesn't not exist in snapshot table.", snapshotKey);
throw new OMException("Snapshot: '{" + snapshotKey + "}' doesn't not exist in snapshot table.", FILE_NOT_FOUND);
}
- volumeName = snapshotInfo.getVolumeName();
- bucketName = snapshotInfo.getBucketName();
- snapshotName = snapshotInfo.getName();
-
- mergeOmLockDetails(metadataManager.getLock()
- .acquireWriteLock(SNAPSHOT_LOCK, volumeName, bucketName, snapshotName));
-
- acquiredSnapshotLock = getOmLockDetails().isLockAcquired();
-
- updatedSnapInfo = metadataManager.getSnapshotInfoTable()
- .get(snapshotKey);
-
if (setSnapshotPropertyRequest.hasDeepCleanedDeletedDir()) {
updatedSnapInfo.setDeepCleanedDeletedDir(setSnapshotPropertyRequest
@@ -126,14 +108,6 @@ public OMClientResponse validateAndUpdateCache(OzoneManager ozoneManager, TermIn
createErrorOMResponse(omResponse, ex));
omMetrics.incNumSnapshotSetPropertyFails();
LOG.error("Failed to execute snapshotSetPropertyRequest: {{}}.", setSnapshotPropertyRequest, ex);
- } finally {
- if (acquiredSnapshotLock) {
- mergeOmLockDetails(metadataManager.getLock()
- .releaseWriteLock(SNAPSHOT_LOCK, volumeName, bucketName, snapshotName));
- }
- if (omClientResponse != null) {
- omClientResponse.setOmLockDetails(getOmLockDetails());
- }
}
return omClientResponse;
diff --git a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/volume/OMQuotaRepairRequest.java b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/volume/OMQuotaRepairRequest.java
new file mode 100644
index 00000000000..e307a1f95fd
--- /dev/null
+++ b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/volume/OMQuotaRepairRequest.java
@@ -0,0 +1,191 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.hadoop.ozone.om.request.volume;
+
+import com.google.common.base.Preconditions;
+import java.io.IOException;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import org.apache.commons.lang3.tuple.Pair;
+import org.apache.hadoop.hdds.utils.db.Table;
+import org.apache.hadoop.hdds.utils.db.TableIterator;
+import org.apache.hadoop.hdds.utils.db.cache.CacheKey;
+import org.apache.hadoop.hdds.utils.db.cache.CacheValue;
+import org.apache.hadoop.ozone.om.OMMetadataManager;
+import org.apache.hadoop.ozone.om.OzoneManager;
+import org.apache.hadoop.ozone.om.exceptions.OMException;
+import org.apache.hadoop.ozone.om.helpers.OmBucketInfo;
+import org.apache.hadoop.ozone.om.helpers.OmVolumeArgs;
+import org.apache.hadoop.ozone.om.request.OMClientRequest;
+import org.apache.hadoop.ozone.om.request.util.OmResponseUtil;
+import org.apache.hadoop.ozone.om.response.OMClientResponse;
+import org.apache.hadoop.ozone.om.response.volume.OMQuotaRepairResponse;
+import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos;
+import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.OMRequest;
+import org.apache.hadoop.security.UserGroupInformation;
+import org.apache.ratis.server.protocol.TermIndex;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import static org.apache.hadoop.ozone.OzoneConsts.OLD_QUOTA_DEFAULT;
+import static org.apache.hadoop.ozone.OzoneConsts.QUOTA_RESET;
+import static org.apache.hadoop.ozone.om.lock.OzoneManagerLock.Resource.BUCKET_LOCK;
+import static org.apache.hadoop.ozone.om.lock.OzoneManagerLock.Resource.VOLUME_LOCK;
+
+/**
+ * Handle OMQuotaRepairRequest Request.
+ */
+public class OMQuotaRepairRequest extends OMClientRequest {
+ private static final Logger LOG =
+ LoggerFactory.getLogger(OMQuotaRepairRequest.class);
+
+ public OMQuotaRepairRequest(OMRequest omRequest) {
+ super(omRequest);
+ }
+
+ @Override
+ public OMRequest preExecute(OzoneManager ozoneManager) throws IOException {
+ UserGroupInformation ugi = createUGIForApi();
+ if (ozoneManager.getAclsEnabled() && !ozoneManager.isAdmin(ugi)) {
+ throw new OMException("Access denied for user " + ugi + ". Admin privilege is required for quota repair.",
+ OMException.ResultCodes.ACCESS_DENIED);
+ }
+ return super.preExecute(ozoneManager);
+ }
+
+ @Override
+ @SuppressWarnings("methodlength")
+ public OMClientResponse validateAndUpdateCache(OzoneManager ozoneManager, TermIndex termIndex) {
+ final long transactionLogIndex = termIndex.getIndex();
+ OzoneManagerProtocolProtos.QuotaRepairRequest quotaRepairRequest =
+ getOmRequest().getQuotaRepairRequest();
+ Preconditions.checkNotNull(quotaRepairRequest);
+
+ OMMetadataManager omMetadataManager = ozoneManager.getMetadataManager();
+ OzoneManagerProtocolProtos.OMResponse.Builder omResponse = OmResponseUtil.getOMResponseBuilder(getOmRequest());
+ Map, OmBucketInfo> bucketMap = new HashMap<>();
+ OMClientResponse omClientResponse = null;
+ try {
+ for (int i = 0; i < quotaRepairRequest.getBucketCountCount(); ++i) {
+ OzoneManagerProtocolProtos.BucketQuotaCount bucketCountInfo = quotaRepairRequest.getBucketCount(i);
+ updateBucketInfo(omMetadataManager, bucketCountInfo, transactionLogIndex, bucketMap);
+ }
+ Map volUpdateMap;
+ if (quotaRepairRequest.getSupportVolumeOldQuota()) {
+ volUpdateMap = updateOldVolumeQuotaSupport(omMetadataManager, transactionLogIndex);
+ } else {
+ volUpdateMap = Collections.emptyMap();
+ }
+ omResponse.setQuotaRepairResponse(
+ OzoneManagerProtocolProtos.QuotaRepairResponse.newBuilder().build());
+ omClientResponse = new OMQuotaRepairResponse(omResponse.build(), volUpdateMap, bucketMap);
+ } catch (IOException ex) {
+ LOG.error("failed to update repair count", ex);
+ omClientResponse = new OMQuotaRepairResponse(createErrorOMResponse(omResponse, ex));
+ } finally {
+ if (omClientResponse != null) {
+ omClientResponse.setOmLockDetails(getOmLockDetails());
+ }
+ }
+
+ return omClientResponse;
+ }
+
+ private void updateBucketInfo(
+ OMMetadataManager omMetadataManager, OzoneManagerProtocolProtos.BucketQuotaCount bucketCountInfo,
+ long transactionLogIndex, Map, OmBucketInfo> bucketMap) throws IOException {
+ // acquire lock.
+ mergeOmLockDetails(omMetadataManager.getLock().acquireWriteLock(
+ BUCKET_LOCK, bucketCountInfo.getVolName(), bucketCountInfo.getBucketName()));
+ boolean acquiredBucketLock = getOmLockDetails().isLockAcquired();
+ try {
+ String bucketKey = omMetadataManager.getBucketKey(bucketCountInfo.getVolName(),
+ bucketCountInfo.getBucketName());
+ OmBucketInfo bucketInfo = omMetadataManager.getBucketTable().get(bucketKey);
+ if (null == bucketInfo) {
+ // bucket might be deleted when running repair count parallel
+ return;
+ }
+ bucketInfo.incrUsedBytes(bucketCountInfo.getDiffUsedBytes());
+ bucketInfo.incrUsedNamespace(bucketCountInfo.getDiffUsedNamespace());
+ if (bucketCountInfo.getSupportOldQuota()) {
+ OmBucketInfo.Builder builder = bucketInfo.toBuilder();
+ if (bucketInfo.getQuotaInBytes() == OLD_QUOTA_DEFAULT) {
+ builder.setQuotaInBytes(QUOTA_RESET);
+ }
+ if (bucketInfo.getQuotaInNamespace() == OLD_QUOTA_DEFAULT) {
+ builder.setQuotaInNamespace(QUOTA_RESET);
+ }
+ bucketInfo = builder.build();
+ }
+
+ omMetadataManager.getBucketTable().addCacheEntry(
+ new CacheKey<>(bucketKey), CacheValue.get(transactionLogIndex, bucketInfo));
+ bucketMap.put(Pair.of(bucketCountInfo.getVolName(), bucketCountInfo.getBucketName()), bucketInfo);
+ } finally {
+ if (acquiredBucketLock) {
+ mergeOmLockDetails(omMetadataManager.getLock()
+ .releaseWriteLock(BUCKET_LOCK, bucketCountInfo.getVolName(), bucketCountInfo.getBucketName()));
+ }
+ }
+ }
+
+ private Map updateOldVolumeQuotaSupport(
+ OMMetadataManager metadataManager, long transactionLogIndex) throws IOException {
+ LOG.info("Starting volume quota support update");
+ Map volUpdateMap = new HashMap<>();
+ try (TableIterator>
+ iterator = metadataManager.getVolumeTable().iterator()) {
+ while (iterator.hasNext()) {
+ Table.KeyValue entry = iterator.next();
+ OmVolumeArgs omVolumeArgs = entry.getValue();
+ if (!(omVolumeArgs.getQuotaInBytes() == OLD_QUOTA_DEFAULT
+ || omVolumeArgs.getQuotaInNamespace() == OLD_QUOTA_DEFAULT)) {
+ continue;
+ }
+ mergeOmLockDetails(metadataManager.getLock().acquireWriteLock(
+ VOLUME_LOCK, omVolumeArgs.getVolume()));
+ boolean acquiredVolumeLock = getOmLockDetails().isLockAcquired();
+ try {
+ boolean isQuotaReset = false;
+ if (omVolumeArgs.getQuotaInBytes() == OLD_QUOTA_DEFAULT) {
+ omVolumeArgs.setQuotaInBytes(QUOTA_RESET);
+ isQuotaReset = true;
+ }
+ if (omVolumeArgs.getQuotaInNamespace() == OLD_QUOTA_DEFAULT) {
+ omVolumeArgs.setQuotaInNamespace(QUOTA_RESET);
+ isQuotaReset = true;
+ }
+ if (isQuotaReset) {
+ metadataManager.getVolumeTable().addCacheEntry(
+ new CacheKey<>(entry.getKey()), CacheValue.get(transactionLogIndex, omVolumeArgs));
+ volUpdateMap.put(entry.getKey(), omVolumeArgs);
+ }
+ } finally {
+ if (acquiredVolumeLock) {
+ mergeOmLockDetails(metadataManager.getLock().releaseWriteLock(VOLUME_LOCK, omVolumeArgs.getVolume()));
+ }
+ }
+ }
+ }
+ LOG.info("Completed volume quota support update for volume count {}", volUpdateMap.size());
+ return volUpdateMap;
+ }
+}
diff --git a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/response/snapshot/OMSnapshotPurgeResponse.java b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/response/snapshot/OMSnapshotPurgeResponse.java
index 45b0c5e0590..ea9e68cc9ad 100644
--- a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/response/snapshot/OMSnapshotPurgeResponse.java
+++ b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/response/snapshot/OMSnapshotPurgeResponse.java
@@ -81,9 +81,9 @@ protected void addToDBBatch(OMMetadataManager omMetadataManager,
OmMetadataManagerImpl metadataManager = (OmMetadataManagerImpl)
omMetadataManager;
+ updateSnapInfo(metadataManager, batchOperation, updatedSnapInfos);
updateSnapInfo(metadataManager, batchOperation,
updatedPreviousAndGlobalSnapInfos);
- updateSnapInfo(metadataManager, batchOperation, updatedSnapInfos);
for (String dbKey: snapshotDbKeys) {
// Skip the cache here because snapshot is purged from cache in OMSnapshotPurgeRequest.
SnapshotInfo snapshotInfo = omMetadataManager
diff --git a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/response/volume/OMQuotaRepairResponse.java b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/response/volume/OMQuotaRepairResponse.java
new file mode 100644
index 00000000000..8fa028d7438
--- /dev/null
+++ b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/response/volume/OMQuotaRepairResponse.java
@@ -0,0 +1,72 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.hadoop.ozone.om.response.volume;
+
+import jakarta.annotation.Nonnull;
+import java.io.IOException;
+import java.util.Map;
+import org.apache.commons.lang3.tuple.Pair;
+import org.apache.hadoop.hdds.utils.db.BatchOperation;
+import org.apache.hadoop.ozone.om.OMMetadataManager;
+import org.apache.hadoop.ozone.om.helpers.OmBucketInfo;
+import org.apache.hadoop.ozone.om.helpers.OmVolumeArgs;
+import org.apache.hadoop.ozone.om.request.volume.OMQuotaRepairRequest;
+import org.apache.hadoop.ozone.om.response.CleanupTableInfo;
+import org.apache.hadoop.ozone.om.response.OMClientResponse;
+import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.OMResponse;
+
+import static org.apache.hadoop.ozone.om.OmMetadataManagerImpl.BUCKET_TABLE;
+import static org.apache.hadoop.ozone.om.OmMetadataManagerImpl.VOLUME_TABLE;
+
+/**
+ * Response for {@link OMQuotaRepairRequest} request.
+ */
+@CleanupTableInfo(cleanupTables = {VOLUME_TABLE, BUCKET_TABLE})
+public class OMQuotaRepairResponse extends OMClientResponse {
+ private Map volumeArgsMap;
+ private Map, OmBucketInfo> volBucketInfoMap;
+
+ /**
+ * for quota failure response update.
+ */
+ public OMQuotaRepairResponse(@Nonnull OMResponse omResponse) {
+ super(omResponse);
+ }
+
+ public OMQuotaRepairResponse(
+ @Nonnull OMResponse omResponse, Map volumeArgsMap,
+ Map, OmBucketInfo> volBucketInfoMap) {
+ super(omResponse);
+ this.volBucketInfoMap = volBucketInfoMap;
+ this.volumeArgsMap = volumeArgsMap;
+ }
+
+ @Override
+ public void addToDBBatch(OMMetadataManager metadataManager,
+ BatchOperation batchOp) throws IOException {
+ for (OmBucketInfo omBucketInfo : volBucketInfoMap.values()) {
+ metadataManager.getBucketTable().putWithBatch(batchOp,
+ metadataManager.getBucketKey(omBucketInfo.getVolumeName(),
+ omBucketInfo.getBucketName()), omBucketInfo);
+ }
+ for (OmVolumeArgs volArgs : volumeArgsMap.values()) {
+ metadataManager.getVolumeTable().putWithBatch(batchOp, volArgs.getVolume(), volArgs);
+ }
+ }
+}
diff --git a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/service/QuotaRepairTask.java b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/service/QuotaRepairTask.java
index 8a8ebd06f4f..b3e64c98c5d 100644
--- a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/service/QuotaRepairTask.java
+++ b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/service/QuotaRepairTask.java
@@ -20,14 +20,18 @@
package org.apache.hadoop.ozone.om.service;
import com.google.common.util.concurrent.UncheckedExecutionException;
+import com.google.protobuf.ServiceException;
+import java.io.File;
import java.io.IOException;
import java.io.UncheckedIOException;
+import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
@@ -36,25 +40,29 @@
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;
-import org.apache.hadoop.hdds.utils.db.BatchOperation;
+import org.apache.commons.io.FileUtils;
+import org.apache.hadoop.hdds.conf.OzoneConfiguration;
+import org.apache.hadoop.hdds.utils.db.DBCheckpoint;
import org.apache.hadoop.hdds.utils.db.Table;
import org.apache.hadoop.hdds.utils.db.TableIterator;
-import org.apache.hadoop.hdds.utils.db.cache.CacheKey;
-import org.apache.hadoop.hdds.utils.db.cache.CacheValue;
import org.apache.hadoop.ozone.om.OMMetadataManager;
+import org.apache.hadoop.ozone.om.OmMetadataManagerImpl;
+import org.apache.hadoop.ozone.om.OzoneManager;
import org.apache.hadoop.ozone.om.helpers.BucketLayout;
+import org.apache.hadoop.ozone.om.helpers.OMRatisHelper;
import org.apache.hadoop.ozone.om.helpers.OmBucketInfo;
import org.apache.hadoop.ozone.om.helpers.OmKeyInfo;
-import org.apache.hadoop.ozone.om.helpers.OmVolumeArgs;
-import org.apache.hadoop.ozone.om.lock.IOzoneManagerLock;
+import org.apache.hadoop.ozone.om.ratis.OzoneManagerRatisServer;
+import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos;
+import org.apache.ratis.protocol.ClientId;
+import org.apache.ratis.protocol.Message;
+import org.apache.ratis.protocol.RaftClientRequest;
+import org.codehaus.jackson.map.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static org.apache.hadoop.ozone.OzoneConsts.OLD_QUOTA_DEFAULT;
import static org.apache.hadoop.ozone.OzoneConsts.OM_KEY_PREFIX;
-import static org.apache.hadoop.ozone.OzoneConsts.QUOTA_RESET;
-import static org.apache.hadoop.ozone.om.lock.OzoneManagerLock.Resource.BUCKET_LOCK;
-import static org.apache.hadoop.ozone.om.lock.OzoneManagerLock.Resource.VOLUME_LOCK;
/**
* Quota repair task.
@@ -64,117 +72,189 @@ public class QuotaRepairTask {
QuotaRepairTask.class);
private static final int BATCH_SIZE = 5000;
private static final int TASK_THREAD_CNT = 3;
- public static final long EPOCH_DEFAULT = -1L;
- private final OMMetadataManager metadataManager;
- private final Map nameBucketInfoMap = new HashMap<>();
- private final Map idBucketInfoMap = new HashMap<>();
+ private static final AtomicBoolean IN_PROGRESS = new AtomicBoolean(false);
+ private static final RepairStatus REPAIR_STATUS = new RepairStatus();
+ private final OzoneManager om;
+ private final AtomicLong runCount = new AtomicLong(0);
private ExecutorService executor;
- private final Map keyCountMap = new ConcurrentHashMap<>();
- private final Map fileCountMap
- = new ConcurrentHashMap<>();
- private final Map directoryCountMap
- = new ConcurrentHashMap<>();
- private final Map oldVolumeKeyNameMap = new HashMap();
+ public QuotaRepairTask(OzoneManager ozoneManager) {
+ this.om = ozoneManager;
+ }
- public QuotaRepairTask(OMMetadataManager metadataManager) {
- this.metadataManager = metadataManager;
+ public CompletableFuture repair() throws Exception {
+ // lock in progress operation and reject any other
+ if (!IN_PROGRESS.compareAndSet(false, true)) {
+ LOG.info("quota repair task already running");
+ return CompletableFuture.supplyAsync(() -> false);
+ }
+ REPAIR_STATUS.reset(runCount.get() + 1);
+ return CompletableFuture.supplyAsync(() -> repairTask());
}
-
- public void repair() throws Exception {
- LOG.info("Starting quota repair task");
- prepareAllVolumeBucketInfo();
- IOzoneManagerLock lock = metadataManager.getLock();
- // thread pool with 3 Table type * (1 task each + 3 thread each)
- executor = Executors.newFixedThreadPool(12);
+ public static String getStatus() {
+ return REPAIR_STATUS.toString();
+ }
+ private boolean repairTask() {
+ LOG.info("Starting quota repair task {}", REPAIR_STATUS);
+ OMMetadataManager activeMetaManager = null;
try {
- nameBucketInfoMap.values().stream().forEach(e -> lock.acquireReadLock(
- BUCKET_LOCK, e.getVolumeName(), e.getBucketName()));
- repairCount();
+ // thread pool with 3 Table type * (1 task each + 3 thread for each task)
+ executor = Executors.newFixedThreadPool(3 * (1 + TASK_THREAD_CNT));
+ OzoneManagerProtocolProtos.QuotaRepairRequest.Builder builder
+ = OzoneManagerProtocolProtos.QuotaRepairRequest.newBuilder();
+ // repair active db
+ activeMetaManager = createActiveDBCheckpoint(om.getMetadataManager(), om.getConfiguration());
+ repairActiveDb(activeMetaManager, builder);
+
+ // TODO: repair snapshots for quota
+
+ // submit request to update
+ ClientId clientId = ClientId.randomId();
+ OzoneManagerProtocolProtos.OMRequest omRequest = OzoneManagerProtocolProtos.OMRequest.newBuilder()
+ .setCmdType(OzoneManagerProtocolProtos.Type.QuotaRepair)
+ .setQuotaRepairRequest(builder.build())
+ .setClientId(clientId.toString())
+ .build();
+ OzoneManagerProtocolProtos.OMResponse response = submitRequest(omRequest, clientId);
+ if (response != null && !response.getSuccess()) {
+ LOG.error("update quota repair count response failed");
+ REPAIR_STATUS.updateStatus("Response for update DB is failed");
+ return false;
+ } else {
+ REPAIR_STATUS.updateStatus(builder, om.getMetadataManager());
+ }
+ } catch (Exception exp) {
+ LOG.error("quota repair count failed", exp);
+ REPAIR_STATUS.updateStatus(exp.toString());
+ return false;
} finally {
- nameBucketInfoMap.values().stream().forEach(e -> lock.releaseReadLock(
- BUCKET_LOCK, e.getVolumeName(), e.getBucketName()));
+ LOG.info("Completed quota repair task {}", REPAIR_STATUS);
executor.shutdown();
- LOG.info("Completed quota repair task");
+ try {
+ if (null != activeMetaManager) {
+ activeMetaManager.stop();
+ }
+ cleanTempCheckPointPath(om.getMetadataManager());
+ } catch (Exception exp) {
+ LOG.error("failed to cleanup", exp);
+ }
+ IN_PROGRESS.set(false);
}
- updateOldVolumeQuotaSupport();
-
- // cleanup epoch added to avoid extra epoch id in cache
- ArrayList epochs = new ArrayList<>();
- epochs.add(EPOCH_DEFAULT);
- metadataManager.getBucketTable().cleanupCache(epochs);
- metadataManager.getVolumeTable().cleanupCache(epochs);
+ return true;
}
-
- private void prepareAllVolumeBucketInfo() throws IOException {
- try (TableIterator>
- iterator = metadataManager.getVolumeTable().iterator()) {
- OmVolumeArgs omVolumeArgs;
- while (iterator.hasNext()) {
- Table.KeyValue entry =
- iterator.next();
- omVolumeArgs = entry.getValue();
- getAllBuckets(omVolumeArgs.getVolume(), omVolumeArgs.getObjectID());
- if (omVolumeArgs.getQuotaInBytes() == OLD_QUOTA_DEFAULT
- || omVolumeArgs.getQuotaInNamespace() == OLD_QUOTA_DEFAULT) {
- oldVolumeKeyNameMap.put(entry.getKey(), entry.getValue().getVolume());
- }
+ private void repairActiveDb(
+ OMMetadataManager metadataManager,
+ OzoneManagerProtocolProtos.QuotaRepairRequest.Builder builder) throws Exception {
+ Map nameBucketInfoMap = new HashMap<>();
+ Map idBucketInfoMap = new HashMap<>();
+ Map oriBucketInfoMap = new HashMap<>();
+ prepareAllBucketInfo(nameBucketInfoMap, idBucketInfoMap, oriBucketInfoMap, metadataManager);
+
+ repairCount(nameBucketInfoMap, idBucketInfoMap, metadataManager);
+
+ // prepare and submit request to ratis
+ for (Map.Entry entry : nameBucketInfoMap.entrySet()) {
+ OmBucketInfo oriBucketInfo = oriBucketInfoMap.get(entry.getKey());
+ OmBucketInfo updatedBuckedInfo = entry.getValue();
+ boolean oldQuota = oriBucketInfo.getQuotaInBytes() == OLD_QUOTA_DEFAULT
+ || oriBucketInfo.getQuotaInNamespace() == OLD_QUOTA_DEFAULT;
+ if (!(oldQuota || isChange(oriBucketInfo, updatedBuckedInfo))) {
+ continue;
}
+ OzoneManagerProtocolProtos.BucketQuotaCount.Builder bucketCountBuilder
+ = OzoneManagerProtocolProtos.BucketQuotaCount.newBuilder();
+ bucketCountBuilder.setVolName(updatedBuckedInfo.getVolumeName());
+ bucketCountBuilder.setBucketName(updatedBuckedInfo.getBucketName());
+ bucketCountBuilder.setDiffUsedBytes(updatedBuckedInfo.getUsedBytes() - oriBucketInfo.getUsedBytes());
+ bucketCountBuilder.setDiffUsedNamespace(
+ updatedBuckedInfo.getUsedNamespace() - oriBucketInfo.getUsedNamespace());
+ bucketCountBuilder.setSupportOldQuota(oldQuota);
+ builder.addBucketCount(bucketCountBuilder.build());
}
+
+ // update volume to support quota
+ builder.setSupportVolumeOldQuota(true);
}
- private void updateOldVolumeQuotaSupport() throws IOException {
- LOG.info("Starting volume quota support update");
- IOzoneManagerLock lock = metadataManager.getLock();
- try (BatchOperation batchOperation = metadataManager.getStore()
- .initBatchOperation()) {
- for (Map.Entry volEntry
- : oldVolumeKeyNameMap.entrySet()) {
- lock.acquireReadLock(VOLUME_LOCK, volEntry.getValue());
- try {
- OmVolumeArgs omVolumeArgs = metadataManager.getVolumeTable().get(
- volEntry.getKey());
- boolean isQuotaReset = false;
- if (omVolumeArgs.getQuotaInBytes() == OLD_QUOTA_DEFAULT) {
- omVolumeArgs.setQuotaInBytes(QUOTA_RESET);
- isQuotaReset = true;
- }
- if (omVolumeArgs.getQuotaInNamespace() == OLD_QUOTA_DEFAULT) {
- omVolumeArgs.setQuotaInNamespace(QUOTA_RESET);
- isQuotaReset = true;
- }
- if (isQuotaReset) {
- metadataManager.getVolumeTable().addCacheEntry(
- new CacheKey<>(volEntry.getKey()),
- CacheValue.get(EPOCH_DEFAULT, omVolumeArgs));
- metadataManager.getVolumeTable().putWithBatch(batchOperation,
- volEntry.getKey(), omVolumeArgs);
- }
- } finally {
- lock.releaseReadLock(VOLUME_LOCK, volEntry.getValue());
- }
+ private OzoneManagerProtocolProtos.OMResponse submitRequest(
+ OzoneManagerProtocolProtos.OMRequest omRequest, ClientId clientId) {
+ try {
+ if (om.isRatisEnabled()) {
+ OzoneManagerRatisServer server = om.getOmRatisServer();
+ RaftClientRequest raftClientRequest = RaftClientRequest.newBuilder()
+ .setClientId(clientId)
+ .setServerId(om.getOmRatisServer().getRaftPeerId())
+ .setGroupId(om.getOmRatisServer().getRaftGroupId())
+ .setCallId(runCount.getAndIncrement())
+ .setMessage(Message.valueOf(OMRatisHelper.convertRequestToByteString(omRequest)))
+ .setType(RaftClientRequest.writeRequestType())
+ .build();
+ return server.submitRequest(omRequest, raftClientRequest);
+ } else {
+ return om.getOmServerProtocol().submitRequest(
+ null, omRequest);
}
- metadataManager.getStore().commitBatchOperation(batchOperation);
+ } catch (ServiceException e) {
+ LOG.error("repair quota count " + omRequest.getCmdType() + " request failed.", e);
}
- LOG.info("Completed volume quota support update");
+ return null;
}
- private void getAllBuckets(String volumeName, long volumeId)
- throws IOException {
- List bucketList = metadataManager.listBuckets(
- volumeName, null, null, Integer.MAX_VALUE, false);
- for (OmBucketInfo bucketInfo : bucketList) {
- bucketInfo.incrUsedNamespace(-bucketInfo.getUsedNamespace());
- bucketInfo.incrUsedBytes(-bucketInfo.getUsedBytes());
- nameBucketInfoMap.put(buildNamePath(volumeName,
- bucketInfo.getBucketName()), bucketInfo);
- idBucketInfoMap.put(buildIdPath(volumeId, bucketInfo.getObjectID()),
- bucketInfo);
+ private OMMetadataManager createActiveDBCheckpoint(
+ OMMetadataManager omMetaManager, OzoneConfiguration conf) throws IOException {
+ // cleanup
+ String parentPath = cleanTempCheckPointPath(omMetaManager);
+
+ // create snapshot
+ DBCheckpoint checkpoint = omMetaManager.getStore().getCheckpoint(parentPath, true);
+ return OmMetadataManagerImpl.createCheckpointMetadataManager(conf, checkpoint);
+ }
+
+ private static String cleanTempCheckPointPath(OMMetadataManager omMetaManager) throws IOException {
+ File dbLocation = omMetaManager.getStore().getDbLocation();
+ if (dbLocation == null) {
+ throw new NullPointerException("db location is null");
+ }
+ String tempData = dbLocation.getParent();
+ if (tempData == null) {
+ throw new NullPointerException("parent db dir is null");
+ }
+ File repairTmpPath = Paths.get(tempData, "temp-repair-quota").toFile();
+ FileUtils.deleteDirectory(repairTmpPath);
+ FileUtils.forceMkdir(repairTmpPath);
+ return repairTmpPath.toString();
+ }
+
+ private void prepareAllBucketInfo(
+ Map nameBucketInfoMap, Map idBucketInfoMap,
+ Map oriBucketInfoMap, OMMetadataManager metadataManager) throws IOException {
+ try (TableIterator>
+ iterator = metadataManager.getBucketTable().iterator()) {
+ while (iterator.hasNext()) {
+ Table.KeyValue entry = iterator.next();
+ OmBucketInfo bucketInfo = entry.getValue();
+ String bucketNameKey = buildNamePath(bucketInfo.getVolumeName(),
+ bucketInfo.getBucketName());
+ oriBucketInfoMap.put(bucketNameKey, bucketInfo.copyObject());
+ bucketInfo.incrUsedNamespace(-bucketInfo.getUsedNamespace());
+ bucketInfo.incrUsedBytes(-bucketInfo.getUsedBytes());
+ nameBucketInfoMap.put(bucketNameKey, bucketInfo);
+ idBucketInfoMap.put(buildIdPath(metadataManager.getVolumeId(bucketInfo.getVolumeName()),
+ bucketInfo.getObjectID()), bucketInfo);
+ }
+ }
+ }
+
+ private boolean isChange(OmBucketInfo lBucketInfo, OmBucketInfo rBucketInfo) {
+ if (lBucketInfo.getUsedNamespace() != rBucketInfo.getUsedNamespace()
+ || lBucketInfo.getUsedBytes() != rBucketInfo.getUsedBytes()) {
+ return true;
}
+ return false;
}
- private String buildNamePath(String volumeName, String bucketName) {
+ private static String buildNamePath(String volumeName, String bucketName) {
final StringBuilder builder = new StringBuilder();
builder.append(OM_KEY_PREFIX)
.append(volumeName)
@@ -184,7 +264,7 @@ private String buildNamePath(String volumeName, String bucketName) {
return builder.toString();
}
- private String buildIdPath(long volumeId, long bucketId) {
+ private static String buildIdPath(long volumeId, long bucketId) {
final StringBuilder builder = new StringBuilder();
builder.append(OM_KEY_PREFIX)
.append(volumeId)
@@ -194,8 +274,13 @@ private String buildIdPath(long volumeId, long bucketId) {
return builder.toString();
}
- private void repairCount() throws Exception {
- LOG.info("Starting quota repair for all keys, files and directories");
+ private void repairCount(
+ Map nameBucketInfoMap, Map idBucketInfoMap,
+ OMMetadataManager metadataManager) throws Exception {
+ LOG.info("Starting quota repair counting for all keys, files and directories");
+ Map keyCountMap = new ConcurrentHashMap<>();
+ Map fileCountMap = new ConcurrentHashMap<>();
+ Map directoryCountMap = new ConcurrentHashMap<>();
try {
nameBucketInfoMap.keySet().stream().forEach(e -> keyCountMap.put(e,
new CountPair()));
@@ -225,51 +310,11 @@ private void repairCount() throws Exception {
throw new Exception(ex.getCause());
}
- // persist bucket info
+ // update count to bucket info
updateCountToBucketInfo(nameBucketInfoMap, keyCountMap);
updateCountToBucketInfo(idBucketInfoMap, fileCountMap);
updateCountToBucketInfo(idBucketInfoMap, directoryCountMap);
-
- // update quota enable flag for old volume and buckets
- updateOldBucketQuotaSupport();
-
- try (BatchOperation batchOperation = metadataManager.getStore()
- .initBatchOperation()) {
- for (Map.Entry entry
- : nameBucketInfoMap.entrySet()) {
- String bucketKey = metadataManager.getBucketKey(
- entry.getValue().getVolumeName(),
- entry.getValue().getBucketName());
- metadataManager.getBucketTable().putWithBatch(batchOperation,
- bucketKey, entry.getValue());
- }
- metadataManager.getStore().commitBatchOperation(batchOperation);
- }
- LOG.info("Completed quota repair for all keys, files and directories");
- }
-
- private void updateOldBucketQuotaSupport() {
- for (Map.Entry entry : nameBucketInfoMap.entrySet()) {
- if (entry.getValue().getQuotaInBytes() == OLD_QUOTA_DEFAULT
- || entry.getValue().getQuotaInNamespace() == OLD_QUOTA_DEFAULT) {
- OmBucketInfo.Builder builder = entry.getValue().toBuilder();
- if (entry.getValue().getQuotaInBytes() == OLD_QUOTA_DEFAULT) {
- builder.setQuotaInBytes(QUOTA_RESET);
- }
- if (entry.getValue().getQuotaInNamespace() == OLD_QUOTA_DEFAULT) {
- builder.setQuotaInNamespace(QUOTA_RESET);
- }
- OmBucketInfo bucketInfo = builder.build();
- entry.setValue(bucketInfo);
-
- // there is a new value to be updated in bucket cache
- String bucketKey = metadataManager.getBucketKey(
- bucketInfo.getVolumeName(), bucketInfo.getBucketName());
- metadataManager.getBucketTable().addCacheEntry(
- new CacheKey<>(bucketKey),
- CacheValue.get(EPOCH_DEFAULT, bucketInfo));
- }
- }
+ LOG.info("Completed quota repair counting for all keys, files and directories");
}
private void recalculateUsages(
@@ -315,7 +360,7 @@ private void recalculateUsages(
}
}
- private void captureCount(
+ private static void captureCount(
Map prefixUsageMap,
BlockingQueue>> q,
AtomicBoolean isRunning, boolean haveValue) throws UncheckedIOException {
@@ -334,7 +379,7 @@ private void captureCount(
}
}
- private void extractCount(
+ private static void extractCount(
Table.KeyValue kv,
Map prefixUsageMap,
boolean haveValue) {
@@ -357,7 +402,7 @@ private void extractCount(
}
}
- private synchronized void updateCountToBucketInfo(
+ private static synchronized void updateCountToBucketInfo(
Map bucketInfoMap,
Map prefixUsageMap) {
for (Map.Entry entry : prefixUsageMap.entrySet()) {
@@ -370,7 +415,7 @@ private synchronized void updateCountToBucketInfo(
}
}
- private String getVolumeBucketPrefix(String key) {
+ private static String getVolumeBucketPrefix(String key) {
// get bucket prefix with ///
// -- as represents name in OBS and id in FSO
String prefix = key;
@@ -404,4 +449,66 @@ public long getNamespace() {
return namespace.get();
}
}
+
+ /**
+ * Repair status for last run.
+ */
+ public static class RepairStatus {
+ private boolean isTriggered = false;
+ private long taskId = 0;
+ private long lastRunStartTime = 0;
+ private long lastRunFinishedTime = 0;
+ private String errorMsg = null;
+ private Map> bucketCountDiffMap = new ConcurrentHashMap<>();
+
+ @Override
+ public String toString() {
+ if (!isTriggered) {
+ return "{}";
+ }
+ Map status = new HashMap<>();
+ status.put("taskId", taskId);
+ status.put("lastRunStartTime", lastRunStartTime);
+ status.put("lastRunFinishedTime", lastRunFinishedTime);
+ status.put("errorMsg", errorMsg);
+ status.put("bucketCountDiffMap", bucketCountDiffMap);
+ try {
+ return new ObjectMapper().writeValueAsString(status);
+ } catch (IOException e) {
+ LOG.error("error in generating status", e);
+ return "{}";
+ }
+ }
+
+ public void updateStatus(OzoneManagerProtocolProtos.QuotaRepairRequest.Builder builder,
+ OMMetadataManager metadataManager) {
+ isTriggered = true;
+ lastRunFinishedTime = System.currentTimeMillis();
+ errorMsg = "";
+ bucketCountDiffMap.clear();
+ for (OzoneManagerProtocolProtos.BucketQuotaCount quotaCount : builder.getBucketCountList()) {
+ String bucketKey = metadataManager.getBucketKey(quotaCount.getVolName(), quotaCount.getBucketName());
+ ConcurrentHashMap diffCountMap = new ConcurrentHashMap<>();
+ diffCountMap.put("DiffUsedBytes", quotaCount.getDiffUsedBytes());
+ diffCountMap.put("DiffUsedNamespace", quotaCount.getDiffUsedNamespace());
+ bucketCountDiffMap.put(bucketKey, diffCountMap);
+ }
+ }
+
+ public void updateStatus(String errMsg) {
+ isTriggered = true;
+ lastRunFinishedTime = System.currentTimeMillis();
+ errorMsg = errMsg;
+ bucketCountDiffMap.clear();
+ }
+
+ public void reset(long tskId) {
+ isTriggered = true;
+ taskId = tskId;
+ lastRunStartTime = System.currentTimeMillis();
+ lastRunFinishedTime = 0;
+ errorMsg = "";
+ bucketCountDiffMap.clear();
+ }
+ }
}
diff --git a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/upgrade/QuotaRepairUpgradeAction.java b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/upgrade/QuotaRepairUpgradeAction.java
index 8a2e4f550e7..446c7382d50 100644
--- a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/upgrade/QuotaRepairUpgradeAction.java
+++ b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/upgrade/QuotaRepairUpgradeAction.java
@@ -21,26 +21,39 @@
import org.apache.hadoop.ozone.om.OMConfigKeys;
import org.apache.hadoop.ozone.om.OzoneManager;
+import org.apache.hadoop.ozone.om.exceptions.OMLeaderNotReadyException;
+import org.apache.hadoop.ozone.om.exceptions.OMNotLeaderException;
import org.apache.hadoop.ozone.om.service.QuotaRepairTask;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import static org.apache.hadoop.ozone.om.upgrade.OMLayoutFeature.QUOTA;
-import static org.apache.hadoop.ozone.upgrade.LayoutFeature.UpgradeActionType.ON_FIRST_UPGRADE_START;
+import static org.apache.hadoop.ozone.upgrade.LayoutFeature.UpgradeActionType.ON_FINALIZE;
/**
- * Quota repair for usages action to be triggered during first upgrade.
+ * Quota repair for usages action to be triggered after upgrade.
*/
-@UpgradeActionOm(type = ON_FIRST_UPGRADE_START, feature =
- QUOTA)
+@UpgradeActionOm(type = ON_FINALIZE, feature = QUOTA)
public class QuotaRepairUpgradeAction implements OmUpgradeAction {
+ private static final Logger LOG = LoggerFactory.getLogger(QuotaRepairUpgradeAction.class);
@Override
public void execute(OzoneManager arg) throws Exception {
boolean enabled = arg.getConfiguration().getBoolean(
OMConfigKeys.OZONE_OM_UPGRADE_QUOTA_RECALCULATE_ENABLE,
OMConfigKeys.OZONE_OM_UPGRADE_QUOTA_RECALCULATE_ENABLE_DEFAULT);
if (enabled) {
- QuotaRepairTask quotaRepairTask = new QuotaRepairTask(
- arg.getMetadataManager());
- quotaRepairTask.repair();
+ // just trigger quota repair and status can be checked via CLI
+ try {
+ if (arg.isRatisEnabled()) {
+ arg.checkLeaderStatus();
+ }
+ QuotaRepairTask quotaRepairTask = new QuotaRepairTask(arg);
+ quotaRepairTask.repair();
+ } catch (OMNotLeaderException | OMLeaderNotReadyException ex) {
+ // on leader node, repair will be triggered where finalize is called. For other nodes, it will be ignored.
+ // This can be triggered on need basis via CLI tool.
+ LOG.warn("Skip quota repair operation during upgrade on the node as this is not a leader node.");
+ }
}
}
}
diff --git a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/protocolPB/OzoneManagerRequestHandler.java b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/protocolPB/OzoneManagerRequestHandler.java
index eb9410501fa..a5e94689aee 100644
--- a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/protocolPB/OzoneManagerRequestHandler.java
+++ b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/protocolPB/OzoneManagerRequestHandler.java
@@ -133,6 +133,7 @@
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.SetSafeModeRequest;
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.SetSafeModeResponse;
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.GetS3VolumeContextResponse;
+import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.ServerDefaultsResponse;
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.Status;
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.SnapshotDiffRequest;
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.SnapshotDiffResponse;
@@ -383,6 +384,12 @@ public OMResponse handleReadRequest(OMRequest request) {
getSnapshotInfo(request.getSnapshotInfoRequest());
responseBuilder.setSnapshotInfoResponse(snapshotInfoResponse);
break;
+ case GetServerDefaults:
+ responseBuilder.setServerDefaultsResponse(
+ ServerDefaultsResponse.newBuilder()
+ .setServerDefaults(impl.getServerDefaults().getProtobuf())
+ .build());
+ break;
default:
responseBuilder.setSuccess(false);
responseBuilder.setMessage("Unrecognized Command Type: " + cmdType);
diff --git a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/security/OMCertificateClient.java b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/security/OMCertificateClient.java
index a6bfed699f7..0a28fc37f3c 100644
--- a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/security/OMCertificateClient.java
+++ b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/security/OMCertificateClient.java
@@ -25,12 +25,12 @@
import org.apache.hadoop.hdds.protocol.proto.SCMSecurityProtocolProtos.SCMGetCertResponseProto;
import org.apache.hadoop.hdds.protocolPB.SCMSecurityProtocolClientSideTranslatorPB;
import org.apache.hadoop.hdds.security.SecurityConfig;
+import org.apache.hadoop.hdds.security.exception.SCMSecurityException;
import org.apache.hadoop.hdds.security.x509.certificate.client.DefaultCertificateClient;
import org.apache.hadoop.hdds.security.x509.certificate.utils.CertificateSignRequest;
import org.apache.hadoop.hdds.security.x509.exception.CertificateException;
import org.apache.hadoop.ozone.om.OMStorage;
import org.apache.hadoop.security.UserGroupInformation;
-import org.bouncycastle.pkcs.PKCS10CertificationRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -38,7 +38,6 @@
import java.security.KeyPair;
import java.util.function.Consumer;
-import static org.apache.hadoop.hdds.security.x509.certificate.utils.CertificateSignRequest.getEncodedString;
/**
* Certificate client for OzoneManager.
@@ -81,9 +80,9 @@ public OMCertificateClient(
* @return CertificateSignRequest.Builder
*/
@Override
- public CertificateSignRequest.Builder getCSRBuilder()
- throws CertificateException {
- CertificateSignRequest.Builder builder = super.getCSRBuilder();
+ public CertificateSignRequest.Builder configureCSRBuilder()
+ throws SCMSecurityException {
+ CertificateSignRequest.Builder builder = super.configureCSRBuilder();
String hostname = omInfo.getHostName();
String subject;
@@ -118,10 +117,8 @@ public CertificateSignRequest.Builder getCSRBuilder()
}
@Override
- protected SCMGetCertResponseProto getCertificateSignResponse(
- PKCS10CertificationRequest request) throws IOException {
- return getScmSecureClient().getOMCertChain(
- omInfo, getEncodedString(request));
+ protected SCMGetCertResponseProto sign(CertificateSignRequest request) throws IOException {
+ return getScmSecureClient().getOMCertChain(omInfo, request.toEncodedFormat());
}
@Override
diff --git a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/TestScmClient.java b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/TestScmClient.java
index 228f668d01a..08d9b9bc2cb 100644
--- a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/TestScmClient.java
+++ b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/TestScmClient.java
@@ -43,7 +43,7 @@
import static com.google.common.collect.Sets.newHashSet;
import static java.util.Arrays.asList;
-import static org.apache.commons.lang.RandomStringUtils.randomAlphabetic;
+import static org.apache.commons.lang3.RandomStringUtils.randomAlphabetic;
import static org.apache.hadoop.hdds.client.ReplicationConfig.fromTypeAndFactor;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
diff --git a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/service/TestKeyDeletingService.java b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/service/TestKeyDeletingService.java
index cf538f581c7..8163592cfc6 100644
--- a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/service/TestKeyDeletingService.java
+++ b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/service/TestKeyDeletingService.java
@@ -34,7 +34,7 @@
import java.util.concurrent.atomic.AtomicLong;
import com.google.common.collect.ImmutableMap;
-import org.apache.commons.lang.RandomStringUtils;
+import org.apache.commons.lang3.RandomStringUtils;
import org.apache.hadoop.hdds.client.RatisReplicationConfig;
import org.apache.hadoop.hdds.utils.db.Table;
import org.apache.hadoop.hdds.utils.db.TableIterator;
diff --git a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/service/TestQuotaRepairTask.java b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/service/TestQuotaRepairTask.java
index 1a0db118331..06b8beacb39 100644
--- a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/service/TestQuotaRepairTask.java
+++ b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/service/TestQuotaRepairTask.java
@@ -22,8 +22,16 @@
import static org.apache.hadoop.hdds.protocol.proto.HddsProtos.ReplicationFactor.ONE;
import static org.apache.hadoop.hdds.protocol.proto.HddsProtos.ReplicationFactor.THREE;
import static org.junit.jupiter.api.Assertions.assertEquals;
-
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.atomic.AtomicReference;
import org.apache.hadoop.hdds.client.RatisReplicationConfig;
+import org.apache.hadoop.hdds.utils.db.BatchOperation;
import org.apache.hadoop.hdds.utils.db.cache.CacheKey;
import org.apache.hadoop.hdds.utils.db.cache.CacheValue;
import org.apache.hadoop.ozone.om.helpers.BucketLayout;
@@ -32,6 +40,11 @@
import org.apache.hadoop.ozone.om.helpers.OmVolumeArgs;
import org.apache.hadoop.ozone.om.request.OMRequestTestUtils;
import org.apache.hadoop.ozone.om.request.key.TestOMKeyRequest;
+import org.apache.hadoop.ozone.om.request.volume.OMQuotaRepairRequest;
+import org.apache.hadoop.ozone.om.response.OMClientResponse;
+import org.apache.hadoop.ozone.om.response.volume.OMQuotaRepairResponse;
+import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos;
+import org.apache.hadoop.ozone.protocolPB.OzoneManagerProtocolServerSideTranslatorPB;
import org.apache.hadoop.util.Time;
import org.junit.jupiter.api.Test;
@@ -44,6 +57,16 @@ public class TestQuotaRepairTask extends TestOMKeyRequest {
@Test
public void testQuotaRepair() throws Exception {
+ when(ozoneManager.isRatisEnabled()).thenReturn(false);
+ OzoneManagerProtocolProtos.OMResponse respMock = mock(OzoneManagerProtocolProtos.OMResponse.class);
+ when(respMock.getSuccess()).thenReturn(true);
+ OzoneManagerProtocolServerSideTranslatorPB serverMock = mock(OzoneManagerProtocolServerSideTranslatorPB.class);
+ AtomicReference ref = new AtomicReference<>();
+ doAnswer(invocation -> {
+ ref.set(invocation.getArgument(1, OzoneManagerProtocolProtos.OMRequest.class));
+ return respMock;
+ }).when(serverMock).submitRequest(any(), any());
+ when(ozoneManager.getOmServerProtocol()).thenReturn(serverMock);
OMRequestTestUtils.addVolumeAndBucketToDB(volumeName, bucketName,
omMetadataManager, BucketLayout.OBJECT_STORE);
@@ -88,9 +111,16 @@ public void testQuotaRepair() throws Exception {
assertEquals(0, fsoBucketInfo.getUsedNamespace());
assertEquals(0, fsoBucketInfo.getUsedBytes());
- QuotaRepairTask quotaRepairTask = new QuotaRepairTask(omMetadataManager);
- quotaRepairTask.repair();
-
+ QuotaRepairTask quotaRepairTask = new QuotaRepairTask(ozoneManager);
+ CompletableFuture repair = quotaRepairTask.repair();
+ Boolean repairStatus = repair.get();
+ assertTrue(repairStatus);
+
+ OMQuotaRepairRequest omQuotaRepairRequest = new OMQuotaRepairRequest(ref.get());
+ OMClientResponse omClientResponse = omQuotaRepairRequest.validateAndUpdateCache(ozoneManager, 1);
+ BatchOperation batchOperation = omMetadataManager.getStore().initBatchOperation();
+ ((OMQuotaRepairResponse)omClientResponse).addToDBBatch(omMetadataManager, batchOperation);
+ omMetadataManager.getStore().commitBatchOperation(batchOperation);
// 10 files of each type, obs have replication of three and
// fso have replication of one
OmBucketInfo obsUpdateBucketInfo = omMetadataManager.getBucketTable().get(
@@ -105,6 +135,16 @@ public void testQuotaRepair() throws Exception {
@Test
public void testQuotaRepairForOldVersionVolumeBucket() throws Exception {
+ when(ozoneManager.isRatisEnabled()).thenReturn(false);
+ OzoneManagerProtocolProtos.OMResponse respMock = mock(OzoneManagerProtocolProtos.OMResponse.class);
+ when(respMock.getSuccess()).thenReturn(true);
+ OzoneManagerProtocolServerSideTranslatorPB serverMock = mock(OzoneManagerProtocolServerSideTranslatorPB.class);
+ AtomicReference ref = new AtomicReference<>();
+ doAnswer(invocation -> {
+ ref.set(invocation.getArgument(1, OzoneManagerProtocolProtos.OMRequest.class));
+ return respMock;
+ }).when(serverMock).submitRequest(any(), any());
+ when(ozoneManager.getOmServerProtocol()).thenReturn(serverMock);
// add volume with -2 value
OmVolumeArgs omVolumeArgs =
OmVolumeArgs.newBuilder().setCreationTime(Time.now())
@@ -117,13 +157,14 @@ public void testQuotaRepairForOldVersionVolumeBucket() throws Exception {
new CacheKey<>(omMetadataManager.getVolumeKey(volumeName)),
CacheValue.get(1L, omVolumeArgs));
- // add bucket with -2 value
+ // add bucket with -2 value and add to db
OMRequestTestUtils.addBucketToDB(volumeName, bucketName,
omMetadataManager, -2);
+ String bucketKey = omMetadataManager.getBucketKey(volumeName, bucketName);
+ omMetadataManager.getBucketTable().put(bucketKey, omMetadataManager.getBucketTable().get(bucketKey));
// pre check for quota flag
- OmBucketInfo bucketInfo = omMetadataManager.getBucketTable().get(
- omMetadataManager.getBucketKey(volumeName, bucketName));
+ OmBucketInfo bucketInfo = omMetadataManager.getBucketTable().get(bucketKey);
assertEquals(-2, bucketInfo.getQuotaInBytes());
omVolumeArgs = omMetadataManager.getVolumeTable().get(
@@ -131,11 +172,18 @@ public void testQuotaRepairForOldVersionVolumeBucket() throws Exception {
assertEquals(-2, omVolumeArgs.getQuotaInBytes());
assertEquals(-2, omVolumeArgs.getQuotaInNamespace());
- QuotaRepairTask quotaRepairTask = new QuotaRepairTask(omMetadataManager);
- quotaRepairTask.repair();
+ QuotaRepairTask quotaRepairTask = new QuotaRepairTask(ozoneManager);
+ CompletableFuture repair = quotaRepairTask.repair();
+ Boolean repairStatus = repair.get();
+ assertTrue(repairStatus);
+ OMQuotaRepairRequest omQuotaRepairRequest = new OMQuotaRepairRequest(ref.get());
+ OMClientResponse omClientResponse = omQuotaRepairRequest.validateAndUpdateCache(ozoneManager, 1);
+ BatchOperation batchOperation = omMetadataManager.getStore().initBatchOperation();
+ ((OMQuotaRepairResponse)omClientResponse).addToDBBatch(omMetadataManager, batchOperation);
+ omMetadataManager.getStore().commitBatchOperation(batchOperation);
bucketInfo = omMetadataManager.getBucketTable().get(
- omMetadataManager.getBucketKey(volumeName, bucketName));
+ bucketKey);
assertEquals(-1, bucketInfo.getQuotaInBytes());
OmVolumeArgs volArgsVerify = omMetadataManager.getVolumeTable()
.get(omMetadataManager.getVolumeKey(volumeName));
diff --git a/hadoop-ozone/ozonefs-common/pom.xml b/hadoop-ozone/ozonefs-common/pom.xml
index 99ab7ba21bf..6132f9bc125 100644
--- a/hadoop-ozone/ozonefs-common/pom.xml
+++ b/hadoop-ozone/ozonefs-common/pom.xml
@@ -43,10 +43,22 @@