blob: 3c707ba1e18bde091d3a4f900eaebfd71a6cac9f [file] [log] [blame]
/*
* 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;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.apache.hadoop.hdds.conf.OzoneConfiguration;
import org.apache.hadoop.hdds.scm.container.common.helpers.ExcludeList;
import org.apache.hadoop.hdds.server.ServerUtils;
import org.apache.hadoop.ozone.om.helpers.OmBucketInfo;
import org.apache.hadoop.ozone.om.helpers.OmKeyArgs;
import org.apache.hadoop.ozone.om.helpers.OmVolumeArgs;
import org.apache.hadoop.ozone.om.helpers.OpenKeySession;
import org.apache.hadoop.ozone.om.request.TestOMRequestUtils;
import org.apache.hadoop.test.GenericTestUtils;
import org.apache.hadoop.hdds.utils.db.DBConfigFromFile;
import org.apache.commons.lang3.RandomStringUtils;
import static org.apache.hadoop.hdds.HddsConfigKeys.HDDS_CONTAINER_REPORT_INTERVAL;
import static org.apache.hadoop.ozone.OzoneConfigKeys.OZONE_BLOCK_DELETING_SERVICE_INTERVAL;
import org.junit.Assert;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
/**
* Test Key Deleting Service.
* <p>
* This test does the following things.
* <p>
* 1. Creates a bunch of keys. 2. Then executes delete key directly using
* Metadata Manager. 3. Waits for a while for the KeyDeleting Service to pick up
* and call into SCM. 4. Confirms that calls have been successful.
*/
public class TestKeyDeletingService {
@Rule
public TemporaryFolder folder = new TemporaryFolder();
private OzoneConfiguration createConfAndInitValues() throws IOException {
OzoneConfiguration conf = new OzoneConfiguration();
File newFolder = folder.newFolder();
if (!newFolder.exists()) {
Assert.assertTrue(newFolder.mkdirs());
}
System.setProperty(DBConfigFromFile.CONFIG_DIR, "/");
ServerUtils.setOzoneMetaDirPath(conf, newFolder.toString());
conf.setTimeDuration(OZONE_BLOCK_DELETING_SERVICE_INTERVAL, 100,
TimeUnit.MILLISECONDS);
conf.setTimeDuration(HDDS_CONTAINER_REPORT_INTERVAL, 200,
TimeUnit.MILLISECONDS);
conf.setQuietMode(false);
return conf;
}
/**
* In this test, we create a bunch of keys and delete them. Then we start the
* KeyDeletingService and pass a SCMClient which does not fail. We make sure
* that all the keys that we deleted is picked up and deleted by
* OzoneManager.
*
* @throws IOException - on Failure.
*/
@Test(timeout = 30000)
public void checkIfDeleteServiceisDeletingKeys()
throws IOException, TimeoutException, InterruptedException {
OzoneConfiguration conf = createConfAndInitValues();
OmMetadataManagerImpl metaMgr = new OmMetadataManagerImpl(conf);
KeyManager keyManager =
new KeyManagerImpl(
new ScmBlockLocationTestingClient(null, null, 0),
metaMgr, conf, UUID.randomUUID().toString(), null);
keyManager.start(conf);
final int keyCount = 100;
createAndDeleteKeys(keyManager, keyCount, 1);
KeyDeletingService keyDeletingService =
(KeyDeletingService) keyManager.getDeletingService();
GenericTestUtils.waitFor(
() -> keyDeletingService.getDeletedKeyCount().get() >= keyCount,
1000, 10000);
Assert.assertTrue(keyDeletingService.getRunCount().get() > 1);
Assert.assertEquals(
keyManager.getPendingDeletionKeys(Integer.MAX_VALUE).size(), 0);
}
@Test(timeout = 30000)
public void checkIfDeleteServiceWithFailingSCM()
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(), null);
keyManager.start(conf);
final int keyCount = 100;
createAndDeleteKeys(keyManager, keyCount, 1);
KeyDeletingService keyDeletingService =
(KeyDeletingService) keyManager.getDeletingService();
keyManager.start(conf);
Assert.assertEquals(
keyManager.getPendingDeletionKeys(Integer.MAX_VALUE).size(), keyCount);
// Make sure that we have run the background thread 5 times more
GenericTestUtils.waitFor(
() -> keyDeletingService.getRunCount().get() >= 5,
100, 1000);
// Since SCM calls are failing, deletedKeyCount should be zero.
Assert.assertEquals(keyDeletingService.getDeletedKeyCount().get(), 0);
Assert.assertEquals(
keyManager.getPendingDeletionKeys(Integer.MAX_VALUE).size(), keyCount);
}
@Test(timeout = 30000)
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(), null);
keyManager.start(conf);
final int keyCount = 100;
createAndDeleteKeys(keyManager, keyCount, 0);
KeyDeletingService keyDeletingService =
(KeyDeletingService) keyManager.getDeletingService();
keyManager.start(conf);
// 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++) {
String volumeName = String.format("volume%s",
RandomStringUtils.randomAlphanumeric(5));
String bucketName = String.format("bucket%s",
RandomStringUtils.randomAlphanumeric(5));
String keyName = String.format("key%s",
RandomStringUtils.randomAlphanumeric(5));
String volumeBytes =
keyManager.getMetadataManager().getVolumeKey(volumeName);
String bucketBytes =
keyManager.getMetadataManager().getBucketKey(volumeName, bucketName);
// cheat here, just create a volume and bucket entry so that we can
// create the keys, we put the same data for key and value since the
// system does not decode the object
TestOMRequestUtils.addVolumeToOM(keyManager.getMetadataManager(),
OmVolumeArgs.newBuilder()
.setOwnerName("o")
.setAdminName("a")
.setVolume(volumeName)
.build());
TestOMRequestUtils.addBucketToOM(keyManager.getMetadataManager(),
OmBucketInfo.newBuilder().setVolumeName(volumeName)
.setBucketName(bucketName)
.build());
OmKeyArgs arg =
new OmKeyArgs.Builder()
.setVolumeName(volumeName)
.setBucketName(bucketName)
.setKeyName(keyName)
.setAcls(Collections.emptyList())
.setLocationInfoList(new ArrayList<>())
.build();
//Open, Commit and Delete the Keys in the Key Manager.
OpenKeySession session = keyManager.openKey(arg);
for (int i = 0; i < numBlocks; i++) {
arg.addLocationInfo(
keyManager.allocateBlock(arg, session.getId(), new ExcludeList()));
}
keyManager.commitKey(arg, session.getId());
keyManager.deleteKey(arg);
}
}
}