-
Notifications
You must be signed in to change notification settings - Fork 518
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
HDDS-11408. Snapshot rename table entries are propagated incorrectly on snapshot deletes #7200
Changes from 4 commits
0335ed2
53a5b5d
87ea520
6675538
96c3daa
535a6cd
7d49b64
f79c5c7
7124b1e
ae0085c
5fb5d8c
67b5a05
4b724fe
e2f0461
8600803
8b477b6
09b9523
7ee74dd
da7701f
b7380e1
e31c153
f6104fd
bc4de22
57d665a
075441b
c3a11a5
bd28a4c
1fd5f1d
d1c0a77
0d0e3e7
554e452
1aa55ff
364663c
9af1e99
0a8183d
73572ad
063f7b7
302491d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -37,6 +37,7 @@ | |
import java.util.Stack; | ||
import java.util.TreeMap; | ||
import java.util.concurrent.TimeUnit; | ||
import java.util.function.Function; | ||
import java.util.stream.Collectors; | ||
import java.util.stream.Stream; | ||
|
||
|
@@ -86,6 +87,7 @@ | |
import org.apache.hadoop.ozone.om.helpers.OzoneFSUtils; | ||
import org.apache.hadoop.ozone.om.helpers.OzoneFileStatus; | ||
import org.apache.hadoop.ozone.om.helpers.BucketLayout; | ||
import org.apache.hadoop.ozone.om.helpers.RepeatedOmKeyInfo; | ||
import org.apache.hadoop.ozone.om.request.OMClientRequest; | ||
import org.apache.hadoop.ozone.om.request.file.OMFileRequest; | ||
import org.apache.hadoop.ozone.om.request.util.OMMultipartUploadUtils; | ||
|
@@ -189,7 +191,7 @@ public class KeyManagerImpl implements KeyManager { | |
|
||
private final KeyProviderCryptoExtension kmsProvider; | ||
private final boolean enableFileSystemPaths; | ||
private BackgroundService dirDeletingService; | ||
private DirectoryDeletingService dirDeletingService; | ||
private final OMPerformanceMetrics metrics; | ||
|
||
private BackgroundService openKeyCleanupService; | ||
|
@@ -662,6 +664,53 @@ public PendingKeysDeletion getPendingDeletionKeys(final int count) | |
.getPendingDeletionKeys(count, ozoneManager.getOmSnapshotManager()); | ||
} | ||
|
||
private <V, R> List<Table.KeyValue<String, R>> getTableEntries(String startKey, | ||
TableIterator<String, ? extends Table.KeyValue<String, V>> tableIterator, | ||
Function<V, R> valueFunction, int count) throws IOException { | ||
List<Table.KeyValue<String, R>> entries = new ArrayList<>(); | ||
/* Seeking to the start key if it not null. The next key picked up would be ensured to start with the bucket | ||
swamirishi marked this conversation as resolved.
Show resolved
Hide resolved
|
||
prefix, {@link org.apache.hadoop.hdds.utils.db.Table#iterator(bucketPrefix)} would ensure this. | ||
*/ | ||
if (startKey != null) { | ||
swamirishi marked this conversation as resolved.
Show resolved
Hide resolved
|
||
tableIterator.seek(startKey); | ||
} | ||
int currentCount = 0; | ||
while (tableIterator.hasNext() && currentCount < count) { | ||
Table.KeyValue<String, V> kv = tableIterator.next(); | ||
if (kv != null) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we need this null check? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No harm in having one. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, there is no harm but it isn't how an iterator is supposed to be used unless null is allowed value in the collection. |
||
entries.add(Table.newKeyValue(kv.getKey(), valueFunction.apply(kv.getValue()))); | ||
currentCount++; | ||
} | ||
} | ||
return entries; | ||
} | ||
|
||
|
||
swamirishi marked this conversation as resolved.
Show resolved
Hide resolved
|
||
@Override | ||
public List<Table.KeyValue<String, String>> getRenamesKeyEntries( | ||
String volume, String bucket, String startKey, int count) throws IOException { | ||
swamirishi marked this conversation as resolved.
Show resolved
Hide resolved
|
||
// Bucket prefix would be empty if volume is empty i.e. either null or "". | ||
Optional<String> bucketPrefix = Optional.ofNullable(volume).map(vol -> vol.isEmpty() ? null : vol) | ||
hemantk-12 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
.map(vol -> metadataManager.getBucketKeyPrefix(vol, bucket)); | ||
try (TableIterator<String, ? extends Table.KeyValue<String, String>> | ||
renamedKeyIter = metadataManager.getSnapshotRenamedTable().iterator(bucketPrefix.orElse(""))) { | ||
return getTableEntries(startKey, renamedKeyIter, Function.identity(), count); | ||
} | ||
} | ||
|
||
@Override | ||
public List<Table.KeyValue<String, List<OmKeyInfo>>> getDeletedKeyEntries( | ||
String volume, String bucket, String startKey, int count) throws IOException { | ||
// Bucket prefix would be empty if volume is empty i.e. either null or "". | ||
Optional<String> bucketPrefix = Optional.ofNullable(volume).map(vol -> vol.isEmpty() ? null : vol) | ||
.map(vol -> metadataManager.getBucketKeyPrefix(vol, bucket)); | ||
hemantk-12 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
List<Table.KeyValue<String, List<OmKeyInfo>>> deletedKeyEntries = new ArrayList<>(count); | ||
swamirishi marked this conversation as resolved.
Show resolved
Hide resolved
|
||
try (TableIterator<String, ? extends Table.KeyValue<String, RepeatedOmKeyInfo>> | ||
delKeyIter = metadataManager.getDeletedTable().iterator(bucketPrefix.orElse(""))) { | ||
return getTableEntries(startKey, delKeyIter, RepeatedOmKeyInfo::cloneOmKeyInfoList, count); | ||
} | ||
} | ||
|
||
@Override | ||
public ExpiredOpenKeys getExpiredOpenKeys(Duration expireThreshold, | ||
int count, BucketLayout bucketLayout, Duration leaseThreshold) throws IOException { | ||
|
@@ -688,7 +737,7 @@ public KeyDeletingService getDeletingService() { | |
} | ||
|
||
@Override | ||
public BackgroundService getDirDeletingService() { | ||
public DirectoryDeletingService getDirDeletingService() { | ||
return dirDeletingService; | ||
} | ||
|
||
|
@@ -1976,6 +2025,20 @@ public Table.KeyValue<String, OmKeyInfo> getPendingDeletionDir() | |
return null; | ||
} | ||
|
||
@Override | ||
public TableIterator<String, ? extends Table.KeyValue<String, OmKeyInfo>> getDeletedDirEntries( | ||
String volume, String bucket) throws IOException { | ||
|
||
// Either both volume & bucket should be null or none of them should be null. | ||
if (!StringUtils.isBlank(volume) && StringUtils.isBlank(bucket) || | ||
hemantk-12 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
StringUtils.isBlank(volume) && !StringUtils.isBlank(bucket)) { | ||
throw new IOException("One of volume : " + volume + ", bucket: " + bucket + " is empty. Either both should be " + | ||
"empty or none of the arguments should be empty"); | ||
} | ||
return StringUtils.isBlank(volume) ? metadataManager.getDeletedDirTable().iterator() : | ||
swamirishi marked this conversation as resolved.
Show resolved
Hide resolved
|
||
metadataManager.getDeletedDirTable().iterator(metadataManager.getBucketKeyPrefixFSO(volume, bucket)); | ||
} | ||
|
||
@Override | ||
public List<OmKeyInfo> getPendingDeletionSubDirs(long volumeId, long bucketId, | ||
OmKeyInfo parentInfo, long numEntries) throws IOException { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: Is there a reason to return the List of Pairs and not the Map? If it is just to maintain the order, LinkedHashMap could be used. I feel that the map improves the readability.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is no reason to creating another map since we are anyways going iterate over it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not asking to create another map. I'm saying the return type could be a map rather than a list of pairs.