Skip to content

Commit 82eeba0

Browse files
ArafatKhan2198xichen01
authored andcommitted
HDDS-7810. Support namespace summaries (du, dist & counts) for OBJECT_STORE buckets. (apache#4245)
(cherry picked from commit 0a5fc69)
1 parent 0d32153 commit 82eeba0

9 files changed

Lines changed: 2216 additions & 16 deletions

File tree

hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/api/handlers/BucketHandler.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -178,9 +178,7 @@ public static BucketHandler getBucketHandler(
178178
omMetadataManager, reconSCM, bucketInfo);
179179
} else if (bucketInfo.getBucketLayout()
180180
.equals(BucketLayout.OBJECT_STORE)) {
181-
// TODO: HDDS-7810 Write a handler for object store bucket
182-
// We can use LegacyBucketHandler for OBS bucket for now.
183-
return new LegacyBucketHandler(reconNamespaceSummaryManager,
181+
return new OBSBucketHandler(reconNamespaceSummaryManager,
184182
omMetadataManager, reconSCM, bucketInfo);
185183
} else {
186184
LOG.error("Unsupported bucket layout: " +

hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/api/handlers/FSOBucketHandler.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
import static org.apache.hadoop.ozone.OzoneConsts.OM_KEY_PREFIX;
4343

4444
/**
45-
* Class for handling FSO buckets.
45+
* Class for handling FSO buckets NameSpaceSummaries.
4646
*/
4747
public class FSOBucketHandler extends BucketHandler {
4848
private static final Logger LOG =

hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/api/handlers/LegacyBucketHandler.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@
4141
import static org.apache.hadoop.ozone.OzoneConsts.OM_KEY_PREFIX;
4242

4343
/**
44-
* Class for handling Legacy buckets.
44+
* Class for handling Legacy buckets NameSpaceSummaries.
4545
*/
4646
public class LegacyBucketHandler extends BucketHandler {
4747

Lines changed: 268 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,268 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
package org.apache.hadoop.ozone.recon.api.handlers;
19+
20+
21+
import org.apache.hadoop.hdds.scm.server.OzoneStorageContainerManager;
22+
import org.apache.hadoop.hdds.utils.db.Table;
23+
import org.apache.hadoop.hdds.utils.db.TableIterator;
24+
import org.apache.hadoop.ozone.om.helpers.BucketLayout;
25+
import org.apache.hadoop.ozone.om.helpers.OmBucketInfo;
26+
import org.apache.hadoop.ozone.om.helpers.OmDirectoryInfo;
27+
import org.apache.hadoop.ozone.om.helpers.OmKeyInfo;
28+
import org.apache.hadoop.ozone.recon.api.types.DUResponse;
29+
import org.apache.hadoop.ozone.recon.api.types.EntityType;
30+
import org.apache.hadoop.ozone.recon.api.types.NSSummary;
31+
import org.apache.hadoop.ozone.recon.recovery.ReconOMMetadataManager;
32+
import org.apache.hadoop.ozone.recon.spi.ReconNamespaceSummaryManager;
33+
34+
import java.io.IOException;
35+
import java.util.List;
36+
37+
import static org.apache.hadoop.ozone.OzoneConsts.OM_KEY_PREFIX;
38+
39+
/**
40+
* Class for handling OBS buckets NameSpaceSummaries.
41+
*/
42+
public class OBSBucketHandler extends BucketHandler {
43+
44+
private final String vol;
45+
private final String bucket;
46+
private final OmBucketInfo omBucketInfo;
47+
48+
public OBSBucketHandler(
49+
ReconNamespaceSummaryManager reconNamespaceSummaryManager,
50+
ReconOMMetadataManager omMetadataManager,
51+
OzoneStorageContainerManager reconSCM,
52+
OmBucketInfo bucketInfo) {
53+
super(reconNamespaceSummaryManager, omMetadataManager,
54+
reconSCM);
55+
this.omBucketInfo = bucketInfo;
56+
this.vol = omBucketInfo.getVolumeName();
57+
this.bucket = omBucketInfo.getBucketName();
58+
}
59+
60+
/**
61+
* Helper function to check if a path is a key, or invalid.
62+
*
63+
* @param keyName key name
64+
* @return KEY, or UNKNOWN
65+
* @throws IOException
66+
*/
67+
@Override
68+
public EntityType determineKeyPath(String keyName) throws IOException {
69+
String key = OM_KEY_PREFIX + vol +
70+
OM_KEY_PREFIX + bucket +
71+
OM_KEY_PREFIX + keyName;
72+
73+
Table<String, OmKeyInfo> keyTable = getKeyTable();
74+
75+
try (
76+
TableIterator<String, ? extends Table.KeyValue<String, OmKeyInfo>>
77+
iterator = keyTable.iterator()) {
78+
iterator.seek(key);
79+
if (iterator.hasNext()) {
80+
Table.KeyValue<String, OmKeyInfo> kv = iterator.next();
81+
String dbKey = kv.getKey();
82+
if (dbKey.equals(key)) {
83+
return EntityType.KEY;
84+
}
85+
}
86+
}
87+
return EntityType.UNKNOWN;
88+
}
89+
90+
/**
91+
* This method handles disk usage of direct keys.
92+
*
93+
* @param parentId The identifier for the parent bucket.
94+
* @param withReplica if withReplica is enabled, set sizeWithReplica
95+
* for each direct key's DU
96+
* @param listFile if listFile is enabled, append key DU as a children
97+
* keys
98+
* @param duData the current DU data
99+
* @param normalizedPath the normalized path request
100+
* @return the total DU of all direct keys
101+
* @throws IOException IOE
102+
*/
103+
@Override
104+
public long handleDirectKeys(long parentId, boolean withReplica,
105+
boolean listFile,
106+
List<DUResponse.DiskUsage> duData,
107+
String normalizedPath) throws IOException {
108+
109+
NSSummary nsSummary = getReconNamespaceSummaryManager()
110+
.getNSSummary(parentId);
111+
// Handle the case of an empty bucket.
112+
if (nsSummary == null) {
113+
return 0;
114+
}
115+
116+
Table<String, OmKeyInfo> keyTable = getKeyTable();
117+
long keyDataSizeWithReplica = 0L;
118+
119+
try (
120+
TableIterator<String, ? extends Table.KeyValue<String, OmKeyInfo>>
121+
iterator = keyTable.iterator()) {
122+
123+
String seekPrefix = OM_KEY_PREFIX +
124+
vol +
125+
OM_KEY_PREFIX +
126+
bucket +
127+
OM_KEY_PREFIX;
128+
129+
iterator.seek(seekPrefix);
130+
131+
while (iterator.hasNext()) {
132+
// KeyName : OmKeyInfo-Object
133+
Table.KeyValue<String, OmKeyInfo> kv = iterator.next();
134+
String dbKey = kv.getKey();
135+
136+
// Exit loop if the key doesn't match the seekPrefix.
137+
if (!dbKey.startsWith(seekPrefix)) {
138+
break;
139+
}
140+
141+
OmKeyInfo keyInfo = kv.getValue();
142+
if (keyInfo != null) {
143+
DUResponse.DiskUsage diskUsage = new DUResponse.DiskUsage();
144+
String objectName = keyInfo.getKeyName();
145+
diskUsage.setSubpath(objectName);
146+
diskUsage.setKey(true);
147+
diskUsage.setSize(keyInfo.getDataSize());
148+
149+
if (withReplica) {
150+
long keyDU = keyInfo.getReplicatedSize();
151+
keyDataSizeWithReplica += keyDU;
152+
diskUsage.setSizeWithReplica(keyDU);
153+
}
154+
// List all the keys for the OBS bucket if requested.
155+
if (listFile) {
156+
duData.add(diskUsage);
157+
}
158+
}
159+
}
160+
}
161+
162+
return keyDataSizeWithReplica;
163+
}
164+
165+
/**
166+
* Calculates the total disk usage (DU) for an Object Store Bucket (OBS) by
167+
* summing the sizes of all keys contained within the bucket.
168+
* Since OBS buckets operate on a flat hierarchy, this method iterates through
169+
* all the keys in the bucket without the need to traverse directories.
170+
*
171+
* @param parentId The identifier for the parent bucket.
172+
* @return The total disk usage of all keys within the specified OBS bucket.
173+
* @throws IOException
174+
*/
175+
@Override
176+
public long calculateDUUnderObject(long parentId) throws IOException {
177+
// Initialize the total disk usage variable.
178+
long totalDU = 0L;
179+
180+
// Access the key table for the bucket.
181+
Table<String, OmKeyInfo> keyTable = getKeyTable();
182+
183+
try (
184+
TableIterator<String, ? extends Table.KeyValue<String, OmKeyInfo>>
185+
iterator = keyTable.iterator()) {
186+
// Construct the seek prefix to filter keys under this bucket.
187+
String seekPrefix =
188+
OM_KEY_PREFIX + vol + OM_KEY_PREFIX + bucket + OM_KEY_PREFIX;
189+
iterator.seek(seekPrefix);
190+
191+
// Iterate over keys in the bucket.
192+
while (iterator.hasNext()) {
193+
Table.KeyValue<String, OmKeyInfo> kv = iterator.next();
194+
String keyName = kv.getKey();
195+
196+
// Break the loop if the current key does not start with the seekPrefix.
197+
if (!keyName.startsWith(seekPrefix)) {
198+
break;
199+
}
200+
201+
// Sum the size of each key to the total disk usage.
202+
OmKeyInfo keyInfo = kv.getValue();
203+
if (keyInfo != null) {
204+
totalDU += keyInfo.getDataSize();
205+
}
206+
}
207+
}
208+
209+
// Return the total disk usage of all keys in the bucket.
210+
return totalDU;
211+
}
212+
213+
/**
214+
* Object stores do not support directories.
215+
*
216+
* @throws UnsupportedOperationException
217+
*/
218+
@Override
219+
public long getDirObjectId(String[] names)
220+
throws UnsupportedOperationException {
221+
throw new UnsupportedOperationException(
222+
"Object stores do not support directories.");
223+
}
224+
225+
/**
226+
* Object stores do not support directories.
227+
*
228+
* @throws UnsupportedOperationException
229+
*/
230+
@Override
231+
public long getDirObjectId(String[] names, int cutoff)
232+
throws UnsupportedOperationException {
233+
throw new UnsupportedOperationException(
234+
"Object stores do not support directories.");
235+
}
236+
237+
/**
238+
* Returns the keyInfo object from the KEY table.
239+
* @return OmKeyInfo
240+
*/
241+
@Override
242+
public OmKeyInfo getKeyInfo(String[] names) throws IOException {
243+
String ozoneKey = OM_KEY_PREFIX;
244+
ozoneKey += String.join(OM_KEY_PREFIX, names);
245+
246+
return getKeyTable().getSkipCache(ozoneKey);
247+
}
248+
249+
/**
250+
* Object stores do not support directories.
251+
*
252+
* @throws UnsupportedOperationException
253+
*/
254+
@Override
255+
public OmDirectoryInfo getDirInfo(String[] names) throws IOException {
256+
throw new UnsupportedOperationException(
257+
"Object stores do not support directories.");
258+
}
259+
260+
public Table<String, OmKeyInfo> getKeyTable() {
261+
return getOmMetadataManager().getKeyTable(getBucketLayout());
262+
}
263+
264+
public BucketLayout getBucketLayout() {
265+
return BucketLayout.OBJECT_STORE;
266+
}
267+
268+
}

hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/tasks/NSSummaryTask.java

Lines changed: 32 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
import java.util.concurrent.Callable;
3939
import java.util.concurrent.Future;
4040
import java.util.concurrent.ThreadFactory;
41+
import java.util.concurrent.TimeUnit;
4142

4243
/**
4344
* Task to query data from OMDB and write into Recon RocksDB.
@@ -68,6 +69,7 @@ public class NSSummaryTask implements ReconOmTask {
6869
private final ReconOMMetadataManager reconOMMetadataManager;
6970
private final NSSummaryTaskWithFSO nsSummaryTaskWithFSO;
7071
private final NSSummaryTaskWithLegacy nsSummaryTaskWithLegacy;
72+
private final NSSummaryTaskWithOBS nsSummaryTaskWithOBS;
7173
private final OzoneConfiguration ozoneConfiguration;
7274

7375
@Inject
@@ -86,6 +88,9 @@ public NSSummaryTask(ReconNamespaceSummaryManager
8688
this.nsSummaryTaskWithLegacy = new NSSummaryTaskWithLegacy(
8789
reconNamespaceSummaryManager,
8890
reconOMMetadataManager, ozoneConfiguration);
91+
this.nsSummaryTaskWithOBS = new NSSummaryTaskWithOBS(
92+
reconNamespaceSummaryManager,
93+
reconOMMetadataManager, ozoneConfiguration);
8994
}
9095

9196
@Override
@@ -95,20 +100,28 @@ public String getTaskName() {
95100

96101
@Override
97102
public Pair<String, Boolean> process(OMUpdateEventBatch events) {
98-
boolean success;
99-
success = nsSummaryTaskWithFSO.processWithFSO(events);
100-
if (success) {
101-
success = nsSummaryTaskWithLegacy.processWithLegacy(events);
102-
} else {
103+
boolean success = nsSummaryTaskWithFSO.processWithFSO(events);
104+
if (!success) {
103105
LOG.error("processWithFSO failed.");
104106
}
107+
success = nsSummaryTaskWithLegacy.processWithLegacy(events);
108+
if (!success) {
109+
LOG.error("processWithLegacy failed.");
110+
}
111+
success = nsSummaryTaskWithOBS.processWithOBS(events);
112+
if (!success) {
113+
LOG.error("processWithOBS failed.");
114+
}
105115
return new ImmutablePair<>(getTaskName(), success);
106116
}
107117

108118
@Override
109119
public Pair<String, Boolean> reprocess(OMMetadataManager omMetadataManager) {
120+
// Initialize a list of tasks to run in parallel
110121
Collection<Callable<Boolean>> tasks = new ArrayList<>();
111122

123+
long startTime = System.nanoTime(); // Record start time
124+
112125
try {
113126
// reinit Recon RocksDB's namespace CF.
114127
reconNamespaceSummaryManager.clearNSSummaryTable();
@@ -122,6 +135,8 @@ public Pair<String, Boolean> reprocess(OMMetadataManager omMetadataManager) {
122135
.reprocessWithFSO(omMetadataManager));
123136
tasks.add(() -> nsSummaryTaskWithLegacy
124137
.reprocessWithLegacy(reconOMMetadataManager));
138+
tasks.add(() -> nsSummaryTaskWithOBS
139+
.reprocessWithOBS(reconOMMetadataManager));
125140

126141
List<Future<Boolean>> results;
127142
ThreadFactory threadFactory = new ThreadFactoryBuilder()
@@ -137,17 +152,25 @@ public Pair<String, Boolean> reprocess(OMMetadataManager omMetadataManager) {
137152
}
138153
}
139154
} catch (InterruptedException ex) {
140-
LOG.error("Error while reprocessing NSSummary " +
141-
"table in Recon DB. ", ex);
155+
LOG.error("Error while reprocessing NSSummary table in Recon DB.", ex);
142156
return new ImmutablePair<>(getTaskName(), false);
143157
} catch (ExecutionException ex2) {
144-
LOG.error("Error while reprocessing NSSummary " +
145-
"table in Recon DB. ", ex2);
158+
LOG.error("Error while reprocessing NSSummary table in Recon DB.", ex2);
146159
return new ImmutablePair<>(getTaskName(), false);
147160
} finally {
148161
executorService.shutdown();
162+
163+
long endTime = System.nanoTime();
164+
// Convert to milliseconds
165+
long durationInMillis =
166+
TimeUnit.NANOSECONDS.toMillis(endTime - startTime);
167+
168+
// Log performance metrics
169+
LOG.info("Task execution time: {} milliseconds", durationInMillis);
149170
}
171+
150172
return new ImmutablePair<>(getTaskName(), true);
151173
}
174+
152175
}
153176

0 commit comments

Comments
 (0)