Skip to content

Commit c696942

Browse files
authored
HDDS-10931. Schedule on demand scan of containers after import (#8550)
1 parent 490e6bb commit c696942

2 files changed

Lines changed: 78 additions & 44 deletions

File tree

hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/replication/ContainerImporter.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,13 +116,16 @@ public void importContainer(long containerID, Path tarFilePath,
116116
}
117117
ContainerUtils.verifyContainerFileChecksum(containerData, conf);
118118
containerData.setVolume(targetVolume);
119+
// lastDataScanTime should be cleared for an imported container
120+
containerData.setDataScanTimestamp(null);
119121

120122
try (InputStream input = Files.newInputStream(tarFilePath)) {
121123
Container container = controller.importContainer(
122124
containerData, input, packer);
123-
// After container import is successful, increase used space for the volume
125+
// After container import is successful, increase used space for the volume and schedule an OnDemand scan for it
124126
targetVolume.incrementUsedSpace(container.getContainerData().getBytesUsed());
125127
containerSet.addContainerByOverwriteMissingContainer(container);
128+
containerSet.scanContainer(containerID);
126129
}
127130
} finally {
128131
importContainerProgress.remove(containerID);

hadoop-hdds/container-service/src/test/java/org/apache/hadoop/ozone/container/replication/TestContainerImporter.java

Lines changed: 74 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,13 @@
2323
import static org.junit.jupiter.api.Assertions.assertEquals;
2424
import static org.junit.jupiter.api.Assertions.assertThrows;
2525
import static org.mockito.ArgumentMatchers.any;
26+
import static org.mockito.Mockito.anyLong;
27+
import static org.mockito.Mockito.atLeastOnce;
28+
import static org.mockito.Mockito.doNothing;
2629
import static org.mockito.Mockito.doReturn;
2730
import static org.mockito.Mockito.mock;
2831
import static org.mockito.Mockito.spy;
32+
import static org.mockito.Mockito.verify;
2933
import static org.mockito.Mockito.when;
3034

3135
import java.io.File;
@@ -35,6 +39,7 @@
3539
import java.nio.charset.StandardCharsets;
3640
import java.nio.file.Files;
3741
import java.util.HashSet;
42+
import java.util.Optional;
3843
import java.util.concurrent.CompletableFuture;
3944
import java.util.concurrent.Semaphore;
4045
import org.apache.commons.compress.archivers.ArchiveOutputStream;
@@ -51,13 +56,15 @@
5156
import org.apache.hadoop.ozone.container.common.impl.ContainerLayoutVersion;
5257
import org.apache.hadoop.ozone.container.common.impl.ContainerSet;
5358
import org.apache.hadoop.ozone.container.common.interfaces.VolumeChoosingPolicy;
59+
import org.apache.hadoop.ozone.container.common.volume.HddsVolume;
5460
import org.apache.hadoop.ozone.container.common.volume.MutableVolumeSet;
5561
import org.apache.hadoop.ozone.container.common.volume.StorageVolume;
5662
import org.apache.hadoop.ozone.container.common.volume.VolumeChoosingPolicyFactory;
5763
import org.apache.hadoop.ozone.container.keyvalue.KeyValueContainer;
5864
import org.apache.hadoop.ozone.container.keyvalue.KeyValueContainerData;
5965
import org.apache.hadoop.ozone.container.keyvalue.TarContainerPacker;
6066
import org.apache.hadoop.ozone.container.ozoneimpl.ContainerController;
67+
import org.apache.hadoop.util.Time;
6168
import org.apache.ozone.test.GenericTestUtils;
6269
import org.junit.jupiter.api.Assertions;
6370
import org.junit.jupiter.api.BeforeEach;
@@ -74,29 +81,41 @@ class TestContainerImporter {
7481

7582
private OzoneConfiguration conf;
7683
private VolumeChoosingPolicy volumeChoosingPolicy;
84+
private KeyValueContainerData containerData;
85+
private KeyValueContainer container;
86+
private ContainerController controllerMock;
87+
private long containerId = 1;
88+
private ContainerSet containerSet;
89+
private MutableVolumeSet volumeSet;
90+
private ContainerImporter containerImporter;
7791

7892
@BeforeEach
79-
void setup() {
93+
void setup() throws IOException {
8094
conf = new OzoneConfiguration();
8195
conf.set(ScmConfigKeys.HDDS_DATANODE_DIR_KEY, tempDir.getAbsolutePath());
8296
volumeChoosingPolicy = VolumeChoosingPolicyFactory.getPolicy(conf);
97+
// create container
98+
containerData = new KeyValueContainerData(containerId,
99+
ContainerLayoutVersion.FILE_PER_BLOCK, 100, "test", "test");
100+
container = new KeyValueContainer(containerData, conf);
101+
controllerMock = mock(ContainerController.class);
102+
when(controllerMock.importContainer(any(ContainerData.class), any(), any())).thenAnswer(
103+
i -> {
104+
containerData = i.getArgument(0);
105+
container = new KeyValueContainer(containerData, conf);
106+
return container;
107+
});
108+
containerSet = spy(newContainerSet(0));
109+
volumeSet = new MutableVolumeSet("test", conf, null,
110+
StorageVolume.VolumeType.DATA_VOLUME, null);
111+
// create containerImporter object
112+
containerImporter = new ContainerImporter(conf,
113+
containerSet, controllerMock, volumeSet, volumeChoosingPolicy);
83114
}
84115

85116
@Test
86117
void importSameContainerWhenAlreadyImport() throws Exception {
87-
long containerId = 1;
88-
// create container
89-
KeyValueContainerData containerData = new KeyValueContainerData(containerId,
90-
ContainerLayoutVersion.FILE_PER_BLOCK, 100, "test", "test");
91-
KeyValueContainer container = new KeyValueContainer(containerData, conf);
92-
ContainerController controllerMock = mock(ContainerController.class);
93-
// create containerImporter object
94-
ContainerSet containerSet = newContainerSet(0);
95118
containerSet.addContainer(container);
96-
MutableVolumeSet volumeSet = new MutableVolumeSet("test", conf, null,
97-
StorageVolume.VolumeType.DATA_VOLUME, null);
98-
ContainerImporter containerImporter = new ContainerImporter(conf,
99-
containerSet, controllerMock, volumeSet, volumeChoosingPolicy);
100119
File tarFile = new File("dummy.tar");
101120
// second import should fail immediately
102121
StorageContainerException ex = assertThrows(StorageContainerException.class,
@@ -108,25 +127,13 @@ void importSameContainerWhenAlreadyImport() throws Exception {
108127

109128
@Test
110129
void importSameContainerWhenFirstInProgress() throws Exception {
111-
long containerId = 1;
112-
// create container
113-
KeyValueContainerData containerData = new KeyValueContainerData(containerId,
114-
ContainerLayoutVersion.FILE_PER_BLOCK, 100, "test", "test");
115-
KeyValueContainer container = new KeyValueContainer(containerData, conf);
116130
// mock controller for return container data with delay
117-
ContainerController controllerMock = mock(ContainerController.class);
118131
Semaphore semaphore = new Semaphore(0);
119132
when(controllerMock.importContainer(any(), any(), any()))
120133
.thenAnswer((invocation) -> {
121134
semaphore.acquire();
122135
return container;
123136
});
124-
// create containerImporter object
125-
ContainerSet containerSet = newContainerSet(0);
126-
MutableVolumeSet volumeSet = new MutableVolumeSet("test", conf, null,
127-
StorageVolume.VolumeType.DATA_VOLUME, null);
128-
ContainerImporter containerImporter = new ContainerImporter(conf,
129-
containerSet, controllerMock, volumeSet, volumeChoosingPolicy);
130137
// run import async first time having delay
131138
File tarFile = containerTarFile(containerId, containerData);
132139
CompletableFuture.runAsync(() -> {
@@ -152,45 +159,69 @@ void importSameContainerWhenFirstInProgress() throws Exception {
152159

153160
@Test
154161
public void testInconsistentChecksumContainerShouldThrowError() throws Exception {
155-
// create container
156-
long containerId = 1;
157-
KeyValueContainerData containerData = spy(new KeyValueContainerData(containerId,
162+
// create container with mock to return different checksums
163+
KeyValueContainerData data = spy(new KeyValueContainerData(containerId,
158164
ContainerLayoutVersion.FILE_PER_BLOCK, 100, "test", "test"));
159165
// mock to return different checksum
160-
when(containerData.getContainerFileChecksum()).thenReturn("checksum1", "checksum2");
161-
// create containerImporter object
162-
ContainerController controllerMock = mock(ContainerController.class);
163-
ContainerSet containerSet = newContainerSet(0);
164-
MutableVolumeSet volumeSet = new MutableVolumeSet("test", conf, null,
165-
StorageVolume.VolumeType.DATA_VOLUME, null);
166-
ContainerImporter containerImporter = spy(new ContainerImporter(conf,
166+
when(data.getContainerFileChecksum()).thenReturn("checksum1", "checksum2");
167+
// create containerImporter object with mock
168+
ContainerImporter importer = spy(new ContainerImporter(conf,
167169
containerSet, controllerMock, volumeSet, volumeChoosingPolicy));
168170

169171
TarContainerPacker packer = mock(TarContainerPacker.class);
170172
when(packer.unpackContainerDescriptor(any())).thenReturn("test".getBytes(
171173
StandardCharsets.UTF_8));
172-
when(containerImporter.getPacker(any())).thenReturn(packer);
174+
when(importer.getPacker(any())).thenReturn(packer);
173175

174-
doReturn(containerData).when(containerImporter).getKeyValueContainerData(any(byte[].class));
175-
when(containerImporter.getImportContainerProgress()).thenReturn(new HashSet<>());
176+
doReturn(data).when(importer).getKeyValueContainerData(any(byte[].class));
177+
when(importer.getImportContainerProgress()).thenReturn(new HashSet<>());
176178

177179
File tarFile = File.createTempFile("temp_" + System
178180
.currentTimeMillis(), ".tar");
179181

180182
StorageContainerException scException =
181183
assertThrows(StorageContainerException.class,
182-
() -> containerImporter.importContainer(containerId,
184+
() -> importer.importContainer(containerId,
183185
tarFile.toPath(), null, NO_COMPRESSION));
184186
Assertions.assertTrue(scException.getMessage().
185187
contains("Container checksum error"));
186188
}
187189

188-
private File containerTarFile(
189-
long containerId, ContainerData containerData) throws IOException {
190+
@Test
191+
public void testImportContainerTriggersOnDemandScanner() throws Exception {
192+
// create containerImporter object
193+
HddsVolume targetVolume = mock(HddsVolume.class);
194+
doNothing().when(targetVolume).incrementUsedSpace(anyLong());
195+
196+
// import the container
197+
File tarFile = containerTarFile(containerId, containerData);
198+
containerImporter.importContainer(containerId, tarFile.toPath(),
199+
targetVolume, NO_COMPRESSION);
200+
201+
verify(containerSet, atLeastOnce()).scanContainer(containerId);
202+
}
203+
204+
@Test
205+
public void testImportContainerResetsLastScanTime() throws Exception {
206+
containerData.setDataScanTimestamp(Time.monotonicNow());
207+
208+
// create containerImporter object
209+
HddsVolume targetVolume = mock(HddsVolume.class);
210+
doNothing().when(targetVolume).incrementUsedSpace(anyLong());
211+
212+
// import the container
213+
File tarFile = containerTarFile(containerId, containerData);
214+
containerImporter.importContainer(containerId, tarFile.toPath(),
215+
targetVolume, NO_COMPRESSION);
216+
217+
assertEquals(Optional.empty(), containerData.lastDataScanTime());
218+
}
219+
220+
private File containerTarFile(long id, ContainerData data) throws IOException {
190221
File yamlFile = new File(tempDir, "container.yaml");
191-
ContainerDataYaml.createContainerFile(containerData, yamlFile);
222+
ContainerDataYaml.createContainerFile(data, yamlFile);
192223
File tarFile = new File(tempDir,
193-
ContainerUtils.getContainerTarName(containerId));
224+
ContainerUtils.getContainerTarName(id));
194225
try (OutputStream output = Files.newOutputStream(tarFile.toPath())) {
195226
ArchiveOutputStream<TarArchiveEntry> archive = new TarArchiveOutputStream(output);
196227
TarArchiveEntry entry = archive.createArchiveEntry(yamlFile,

0 commit comments

Comments
 (0)