HDDS-397. Handle deletion for keys with no blocks. Contributed by Lokesh Jain.
This commit is contained in:
parent
527288ef89
commit
396ce7b884
@ -32,6 +32,8 @@
|
|||||||
import org.apache.hadoop.ozone.om.helpers.OmKeyLocationInfo;
|
import org.apache.hadoop.ozone.om.helpers.OmKeyLocationInfo;
|
||||||
import org.apache.hadoop.ozone.om.helpers.OmKeyLocationInfoGroup;
|
import org.apache.hadoop.ozone.om.helpers.OmKeyLocationInfoGroup;
|
||||||
import org.apache.hadoop.ozone.om.helpers.OpenKeySession;
|
import org.apache.hadoop.ozone.om.helpers.OpenKeySession;
|
||||||
|
import org.apache.hadoop.ozone.protocol.proto
|
||||||
|
.OzoneManagerProtocolProtos.KeyLocationList;
|
||||||
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.KeyInfo;
|
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.KeyInfo;
|
||||||
import org.apache.hadoop.util.Time;
|
import org.apache.hadoop.util.Time;
|
||||||
import org.apache.hadoop.utils.BackgroundService;
|
import org.apache.hadoop.utils.BackgroundService;
|
||||||
@ -447,6 +449,15 @@ public void deleteKey(OmKeyArgs args) throws IOException {
|
|||||||
if (objectValue == null) {
|
if (objectValue == null) {
|
||||||
throw new OMException("Key not found",
|
throw new OMException("Key not found",
|
||||||
OMException.ResultCodes.FAILED_KEY_NOT_FOUND);
|
OMException.ResultCodes.FAILED_KEY_NOT_FOUND);
|
||||||
|
} else {
|
||||||
|
// directly delete key with no blocks from db. This key need not be
|
||||||
|
// moved to deleted table.
|
||||||
|
KeyInfo keyInfo = KeyInfo.parseFrom(objectValue);
|
||||||
|
if (isKeyEmpty(keyInfo)) {
|
||||||
|
metadataManager.getKeyTable().delete(objectKey);
|
||||||
|
LOG.debug("Key {} deleted from OM DB", keyName);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
metadataManager.getStore().move(objectKey,
|
metadataManager.getStore().move(objectKey,
|
||||||
metadataManager.getKeyTable(),
|
metadataManager.getKeyTable(),
|
||||||
@ -463,6 +474,15 @@ public void deleteKey(OmKeyArgs args) throws IOException {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isKeyEmpty(KeyInfo keyInfo) {
|
||||||
|
for (KeyLocationList keyLocationList : keyInfo.getKeyLocationListList()) {
|
||||||
|
if (keyLocationList.getKeyLocationsCount() != 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<OmKeyInfo> listKeys(String volumeName, String bucketName,
|
public List<OmKeyInfo> listKeys(String volumeName, String bucketName,
|
||||||
String startKey, String keyPrefix,
|
String startKey, String keyPrefix,
|
||||||
|
@ -585,14 +585,6 @@ public List<BlockGroup> getPendingDeletionKeys(final int keyCount)
|
|||||||
OmKeyInfo.getFromProtobuf(KeyInfo.parseFrom(kv.getValue()));
|
OmKeyInfo.getFromProtobuf(KeyInfo.parseFrom(kv.getValue()));
|
||||||
// Get block keys as a list.
|
// Get block keys as a list.
|
||||||
OmKeyLocationInfoGroup latest = info.getLatestVersionLocations();
|
OmKeyLocationInfoGroup latest = info.getLatestVersionLocations();
|
||||||
if (latest == null) {
|
|
||||||
// This means that we have a key without any blocks.
|
|
||||||
// BUG-BUG: if this happens the key will never be deleted.
|
|
||||||
// TODO: Right thing to do is to remove this key right here.
|
|
||||||
LOG.warn("Found a key without blocks: {}, skipping for now.",
|
|
||||||
DFSUtil.bytes2String(kv.getKey()));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
List<BlockID> item = latest.getLocationList().stream()
|
List<BlockID> item = latest.getLocationList().stream()
|
||||||
.map(b -> new BlockID(b.getContainerID(), b.getLocalID()))
|
.map(b -> new BlockID(b.getContainerID(), b.getLocalID()))
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
|
@ -33,6 +33,7 @@
|
|||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.TimeoutException;
|
import java.util.concurrent.TimeoutException;
|
||||||
@ -91,14 +92,18 @@ public void checkIfDeleteServiceisDeletingKeys()
|
|||||||
new ScmBlockLocationTestIngClient(null, null, 0),
|
new ScmBlockLocationTestIngClient(null, null, 0),
|
||||||
metaMgr, conf, UUID.randomUUID().toString());
|
metaMgr, conf, UUID.randomUUID().toString());
|
||||||
final int keyCount = 100;
|
final int keyCount = 100;
|
||||||
createAndDeleteKeys(keyManager, keyCount);
|
createAndDeleteKeys(keyManager, keyCount, 1);
|
||||||
KeyDeletingService keyDeletingService =
|
KeyDeletingService keyDeletingService =
|
||||||
(KeyDeletingService) keyManager.getDeletingService();
|
(KeyDeletingService) keyManager.getDeletingService();
|
||||||
keyManager.start();
|
keyManager.start();
|
||||||
|
Assert.assertEquals(
|
||||||
|
keyManager.getPendingDeletionKeys(Integer.MAX_VALUE).size(), keyCount);
|
||||||
GenericTestUtils.waitFor(
|
GenericTestUtils.waitFor(
|
||||||
() -> keyDeletingService.getDeletedKeyCount().get() >= keyCount,
|
() -> keyDeletingService.getDeletedKeyCount().get() >= keyCount,
|
||||||
1000, 10000);
|
1000, 10000);
|
||||||
Assert.assertTrue(keyDeletingService.getRunCount().get() > 1);
|
Assert.assertTrue(keyDeletingService.getRunCount().get() > 1);
|
||||||
|
Assert.assertEquals(
|
||||||
|
keyManager.getPendingDeletionKeys(Integer.MAX_VALUE).size(), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(timeout = 30000)
|
@Test(timeout = 30000)
|
||||||
@ -112,22 +117,51 @@ public void checkIfDeleteServiceWithFailingSCM()
|
|||||||
new ScmBlockLocationTestIngClient(null, null, 1),
|
new ScmBlockLocationTestIngClient(null, null, 1),
|
||||||
metaMgr, conf, UUID.randomUUID().toString());
|
metaMgr, conf, UUID.randomUUID().toString());
|
||||||
final int keyCount = 100;
|
final int keyCount = 100;
|
||||||
createAndDeleteKeys(keyManager, keyCount);
|
createAndDeleteKeys(keyManager, keyCount, 1);
|
||||||
KeyDeletingService keyDeletingService =
|
KeyDeletingService keyDeletingService =
|
||||||
(KeyDeletingService) keyManager.getDeletingService();
|
(KeyDeletingService) keyManager.getDeletingService();
|
||||||
keyManager.start();
|
keyManager.start();
|
||||||
|
Assert.assertEquals(
|
||||||
|
keyManager.getPendingDeletionKeys(Integer.MAX_VALUE).size(), keyCount);
|
||||||
// Make sure that we have run the background thread 5 times more
|
// Make sure that we have run the background thread 5 times more
|
||||||
GenericTestUtils.waitFor(
|
GenericTestUtils.waitFor(
|
||||||
() -> keyDeletingService.getRunCount().get() >= 5,
|
() -> keyDeletingService.getRunCount().get() >= 5,
|
||||||
100, 1000);
|
100, 1000);
|
||||||
// Since SCM calls are failing, deletedKeyCount should be zero.
|
// Since SCM calls are failing, deletedKeyCount should be zero.
|
||||||
Assert.assertEquals(keyDeletingService.getDeletedKeyCount().get(), 0);
|
Assert.assertEquals(keyDeletingService.getDeletedKeyCount().get(), 0);
|
||||||
|
Assert.assertEquals(
|
||||||
|
keyManager.getPendingDeletionKeys(Integer.MAX_VALUE).size(), keyCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createAndDeleteKeys(KeyManager keyManager, int keyCount)
|
@Test(timeout = 30000)
|
||||||
throws IOException {
|
public void checkDeletionForEmptyKey()
|
||||||
|
throws IOException, TimeoutException, InterruptedException {
|
||||||
|
OzoneConfiguration conf = createConfAndInitValues();
|
||||||
|
OmMetadataManagerImpl metaMgr = new OmMetadataManagerImpl(conf);
|
||||||
|
//failCallsFrequency = 1 , means all calls fail.
|
||||||
|
KeyManager keyManager =
|
||||||
|
new KeyManagerImpl(
|
||||||
|
new ScmBlockLocationTestIngClient(null, null, 1),
|
||||||
|
metaMgr, conf, UUID.randomUUID().toString());
|
||||||
|
final int keyCount = 100;
|
||||||
|
createAndDeleteKeys(keyManager, keyCount, 0);
|
||||||
|
KeyDeletingService keyDeletingService =
|
||||||
|
(KeyDeletingService) keyManager.getDeletingService();
|
||||||
|
keyManager.start();
|
||||||
|
|
||||||
|
// Since empty keys are directly deleted from db there should be no
|
||||||
|
// pending deletion keys. Also deletedKeyCount should be zero.
|
||||||
|
Assert.assertEquals(
|
||||||
|
keyManager.getPendingDeletionKeys(Integer.MAX_VALUE).size(), 0);
|
||||||
|
// Make sure that we have run the background thread 2 times or more
|
||||||
|
GenericTestUtils.waitFor(
|
||||||
|
() -> keyDeletingService.getRunCount().get() >= 2,
|
||||||
|
100, 1000);
|
||||||
|
Assert.assertEquals(keyDeletingService.getDeletedKeyCount().get(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createAndDeleteKeys(KeyManager keyManager, int keyCount,
|
||||||
|
int numBlocks) throws IOException {
|
||||||
for (int x = 0; x < keyCount; x++) {
|
for (int x = 0; x < keyCount; x++) {
|
||||||
String volumeName = String.format("volume%s",
|
String volumeName = String.format("volume%s",
|
||||||
RandomStringUtils.randomAlphanumeric(5));
|
RandomStringUtils.randomAlphanumeric(5));
|
||||||
@ -153,10 +187,13 @@ private void createAndDeleteKeys(KeyManager keyManager, int keyCount)
|
|||||||
.setVolumeName(volumeName)
|
.setVolumeName(volumeName)
|
||||||
.setBucketName(bucketName)
|
.setBucketName(bucketName)
|
||||||
.setKeyName(keyName)
|
.setKeyName(keyName)
|
||||||
|
.setLocationInfoList(new ArrayList<>())
|
||||||
.build();
|
.build();
|
||||||
//Open, Commit and Delete the Keys in the Key Manager.
|
//Open, Commit and Delete the Keys in the Key Manager.
|
||||||
OpenKeySession session = keyManager.openKey(arg);
|
OpenKeySession session = keyManager.openKey(arg);
|
||||||
arg.addLocationInfo(keyManager.allocateBlock(arg, session.getId()));
|
for (int i = 0; i < numBlocks; i++) {
|
||||||
|
arg.addLocationInfo(keyManager.allocateBlock(arg, session.getId()));
|
||||||
|
}
|
||||||
keyManager.commitKey(arg, session.getId());
|
keyManager.commitKey(arg, session.getId());
|
||||||
keyManager.deleteKey(arg);
|
keyManager.deleteKey(arg);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user