Skip to content

Commit 33c62f8

Browse files
Hexiaoqiaojojochuang
authored andcommitted
HDFS-14497. Write lock held by metasave impact following RPC processing. Contributed by He Xiaoqiao.
Signed-off-by: Wei-Chiu Chuang <[email protected]>
1 parent 6f5a36c commit 33c62f8

File tree

3 files changed

+79
-11
lines changed

3 files changed

+79
-11
lines changed

hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/blockmanagement/BlockManager.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -733,7 +733,7 @@ public BlockPlacementPolicy getBlockPlacementPolicy() {
733733

734734
/** Dump meta data to out. */
735735
public void metaSave(PrintWriter out) {
736-
assert namesystem.hasWriteLock(); // TODO: block manager read lock and NS write lock
736+
assert namesystem.hasReadLock(); // TODO: block manager read lock and NS write lock
737737
final List<DatanodeDescriptor> live = new ArrayList<DatanodeDescriptor>();
738738
final List<DatanodeDescriptor> dead = new ArrayList<DatanodeDescriptor>();
739739
datanodeManager.fetchDatanodes(live, dead, false);

hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/namenode/FSNamesystem.java

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -592,6 +592,12 @@ private void logAuditEvent(boolean succeeded,
592592
private boolean resourceLowSafeMode = false;
593593
private String nameNodeHostName = null;
594594

595+
/**
596+
* HDFS-14497: Concurrency control when many metaSave request to write
597+
* meta to same out stream after switch to read lock.
598+
*/
599+
private Object metaSaveLock = new Object();
600+
595601
/**
596602
* Notify that loading of this FSDirectory is complete, and
597603
* it is imageLoaded for use
@@ -1769,24 +1775,26 @@ void metaSave(String filename) throws IOException {
17691775
String operationName = "metaSave";
17701776
checkSuperuserPrivilege(operationName);
17711777
checkOperation(OperationCategory.READ);
1772-
writeLock();
1778+
readLock();
17731779
try {
17741780
checkOperation(OperationCategory.READ);
1775-
File file = new File(System.getProperty("hadoop.log.dir"), filename);
1776-
PrintWriter out = new PrintWriter(new BufferedWriter(
1777-
new OutputStreamWriter(Files.newOutputStream(file.toPath()),
1778-
Charsets.UTF_8)));
1779-
metaSave(out);
1780-
out.flush();
1781-
out.close();
1781+
synchronized(metaSaveLock) {
1782+
File file = new File(System.getProperty("hadoop.log.dir"), filename);
1783+
PrintWriter out = new PrintWriter(new BufferedWriter(
1784+
new OutputStreamWriter(Files.newOutputStream(file.toPath()),
1785+
Charsets.UTF_8)));
1786+
metaSave(out);
1787+
out.flush();
1788+
out.close();
1789+
}
17821790
} finally {
1783-
writeUnlock(operationName);
1791+
readUnlock(operationName);
17841792
}
17851793
logAuditEvent(true, operationName, null);
17861794
}
17871795

17881796
private void metaSave(PrintWriter out) {
1789-
assert hasWriteLock();
1797+
assert hasReadLock();
17901798
long totalInodes = this.dir.totalInodes();
17911799
long totalBlocks = this.getBlocksTotal();
17921800
out.println(totalInodes + " files and directories, " + totalBlocks

hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/server/namenode/TestMetaSave.java

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import java.io.FileInputStream;
2828
import java.io.IOException;
2929
import java.io.InputStreamReader;
30+
import java.util.ArrayList;
3031
import java.util.concurrent.TimeoutException;
3132

3233
import com.google.common.base.Supplier;
@@ -215,6 +216,65 @@ public void testMetaSaveOverwrite() throws Exception {
215216
}
216217
}
217218

219+
class MetaSaveThread extends Thread {
220+
NamenodeProtocols nnRpc;
221+
String filename;
222+
public MetaSaveThread(NamenodeProtocols nnRpc, String filename) {
223+
this.nnRpc = nnRpc;
224+
this.filename = filename;
225+
}
226+
227+
@Override
228+
public void run() {
229+
try {
230+
nnRpc.metaSave(filename);
231+
} catch (IOException e) {
232+
}
233+
}
234+
}
235+
236+
/**
237+
* Tests that metasave concurrent output file (not append).
238+
*/
239+
@Test
240+
public void testConcurrentMetaSave() throws Exception {
241+
ArrayList<MetaSaveThread> threads = new ArrayList<>();
242+
for (int i = 0; i < 10; i++) {
243+
threads.add(new MetaSaveThread(nnRpc, "metaSaveConcurrent.out.txt"));
244+
}
245+
for (int i = 0; i < 10; i++) {
246+
threads.get(i).start();
247+
}
248+
for (int i = 0; i < 10; i++) {
249+
threads.get(i).join();
250+
}
251+
// Read output file.
252+
FileInputStream fis = null;
253+
InputStreamReader isr = null;
254+
BufferedReader rdr = null;
255+
try {
256+
fis = new FileInputStream(getLogFile("metaSaveConcurrent.out.txt"));
257+
isr = new InputStreamReader(fis);
258+
rdr = new BufferedReader(isr);
259+
260+
// Validate that file was overwritten (not appended) by checking for
261+
// presence of only one "Live Datanodes" line.
262+
boolean foundLiveDatanodesLine = false;
263+
String line = rdr.readLine();
264+
while (line != null) {
265+
if (line.startsWith("Live Datanodes")) {
266+
if (foundLiveDatanodesLine) {
267+
fail("multiple Live Datanodes lines, output file not overwritten");
268+
}
269+
foundLiveDatanodesLine = true;
270+
}
271+
line = rdr.readLine();
272+
}
273+
} finally {
274+
IOUtils.cleanup(null, rdr, isr, fis);
275+
}
276+
}
277+
218278
@After
219279
public void tearDown() throws IOException {
220280
if (fileSys != null)

0 commit comments

Comments
 (0)