Skip to content

Commit bbffabc

Browse files
committed
[WIP] SnapshotFormatter: New --load-db flag; also load transaction logs
1 parent 0e9c2db commit bbffabc

File tree

1 file changed

+104
-37
lines changed

1 file changed

+104
-37
lines changed

zookeeper-server/src/main/java/org/apache/zookeeper/server/SnapshotFormatter.java

Lines changed: 104 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import java.io.IOException;
2525
import java.io.InputStream;
2626
import java.util.Base64;
27+
import java.util.Collection;
2728
import java.util.Date;
2829
import java.util.HashMap;
2930
import java.util.LinkedList;
@@ -44,6 +45,7 @@
4445
import org.apache.zookeeper.data.ACL;
4546
import org.apache.zookeeper.data.StatPersisted;
4647
import org.apache.zookeeper.server.persistence.FileSnap;
48+
import org.apache.zookeeper.server.persistence.FileTxnSnapLog;
4749
import org.apache.zookeeper.server.persistence.SnapStream;
4850
import org.apache.zookeeper.server.persistence.Util;
4951
import org.apache.zookeeper.util.ServiceUtils;
@@ -57,6 +59,14 @@
5759
*/
5860
@InterfaceAudience.Public
5961
public class SnapshotFormatter {
62+
public interface Processor<A> {
63+
A apply(DataTree dataTree, Map<Long, Integer> sessions, long lastZxid, A acc) throws IOException;
64+
}
65+
66+
public interface Fold<A> {
67+
A apply(DataTree dataTree, String path, A acc) throws IOException;
68+
}
69+
6070
private static final Logger LOG = LoggerFactory.getLogger(SnapshotFormatter.class);
6171

6272
private static final String OPT_DUMP_DATA = "d";
@@ -65,9 +75,22 @@ public class SnapshotFormatter {
6575

6676
private static final String OPT_DUMP_ACLS = "dump-acls";
6777

78+
private static final String OPT_LOAD_DB = "load-db";
79+
80+
private static final String OPT_DATA_LOG_DIR = "data-log-dir";
81+
6882
// per-znode counter so ncdu treats each as a unique object
6983
private static Integer INODE_IDX = 1000;
7084

85+
private final String snapOrSnapDir;
86+
87+
private final CommandLine commandLine;
88+
89+
private SnapshotFormatter(String snapOrSnapDir, CommandLine commandLine) {
90+
this.snapOrSnapDir = snapOrSnapDir;
91+
this.commandLine = commandLine;
92+
}
93+
7194
/**
7295
* USAGE: SnapshotFormatter snapshot_file or the ready-made script: zkSnapShotToolkit.sh
7396
*/
@@ -95,12 +118,6 @@ public static void main(String[] args) throws Exception {
95118
return;
96119
}
97120

98-
String error = ZKUtil.validateFileInput(snapshotFile);
99-
if (null != error) {
100-
LOG.error(error);
101-
ServiceUtils.requestSystemExit(ExitCode.INVALID_INVOCATION.getValue());
102-
}
103-
104121
if (cl.hasOption(OPT_DUMP_DATA) && cl.hasOption(OPT_JSON)) {
105122
LOG.error("Cannot specify both data dump (-d) and json mode (-json) in same call");
106123
ServiceUtils.requestSystemExit(ExitCode.INVALID_INVOCATION.getValue());
@@ -130,6 +147,20 @@ private static Options createOptions() {
130147
.desc("Dump the ACL entries for each znode")
131148
.build());
132149

150+
options.addOption(
151+
Option.builder()
152+
.longOpt(OPT_LOAD_DB)
153+
.desc("Also load transaction logs")
154+
.build());
155+
156+
options.addOption(
157+
Option.builder()
158+
.longOpt(OPT_DATA_LOG_DIR)
159+
.desc("Look for --load-db transaction logs in <dir>")
160+
.hasArg()
161+
.argName("dir")
162+
.build());
163+
133164
return options;
134165
}
135166

@@ -150,17 +181,45 @@ private static void showUsage(Options options, ParseException x) {
150181
ServiceUtils.requestSystemExit(exitCode.getValue());
151182
}
152183

153-
private final String snapshotFileName;
184+
public void run() throws IOException {
185+
Object acc = this;
186+
apply(this::builtinProcessor, acc);
187+
}
154188

155-
private final CommandLine commandLine;
189+
public <A> A apply(Processor<A> processor, A acc) throws IOException {
190+
if (commandLine.hasOption(OPT_LOAD_DB)) {
191+
return processDataBase(processor, acc);
192+
} else {
193+
return processSnapshot(processor, acc);
194+
}
195+
}
156196

157-
private SnapshotFormatter(String snapshotFileName, CommandLine commandLine) {
158-
this.snapshotFileName = snapshotFileName;
159-
this.commandLine = commandLine;
197+
private <A> A processDataBase(Processor<A> processor, A acc) throws IOException {
198+
File snapDir = new File(snapOrSnapDir);
199+
200+
File dataLogDir = snapDir;
201+
if (commandLine.hasOption(OPT_DATA_LOG_DIR)) {
202+
dataLogDir =
203+
new File (commandLine.getOptionValue(OPT_DATA_LOG_DIR));
204+
}
205+
206+
FileTxnSnapLog snapLog =
207+
new FileTxnSnapLog(dataLogDir, snapDir, /* forWrite */ false);
208+
ZKDatabase zkDb = new ZKDatabase(snapLog);
209+
210+
long lastZxid = zkDb.loadDataBase();
211+
212+
return processor.apply(zkDb.getDataTree(), zkDb.getSessionWithTimeOuts(), lastZxid, acc);
160213
}
161214

162-
public void run() throws IOException {
163-
File snapshotFile = new File(snapshotFileName);
215+
private <A> A processSnapshot(Processor<A> processor, A acc) throws IOException {
216+
String error = ZKUtil.validateFileInput(snapOrSnapDir);
217+
if (null != error) {
218+
LOG.error(error);
219+
ServiceUtils.requestSystemExit(ExitCode.INVALID_INVOCATION.getValue());
220+
}
221+
222+
File snapshotFile = new File(snapOrSnapDir);
164223
try (InputStream is = SnapStream.getInputStream(snapshotFile)) {
165224
InputArchive ia = BinaryInputArchive.getArchive(is);
166225

@@ -170,15 +229,29 @@ public void run() throws IOException {
170229
FileSnap.deserialize(dataTree, sessions, ia);
171230
long fileNameZxid = Util.getZxidFromName(snapshotFile.getName(), SNAPSHOT_FILE_PREFIX);
172231

173-
if (commandLine.hasOption(OPT_JSON)) {
174-
printSnapshotJson(dataTree);
175-
} else {
176-
printDetails(dataTree, sessions, fileNameZxid);
177-
}
232+
return processor.apply(dataTree, sessions, fileNameZxid, acc);
233+
}
234+
}
235+
236+
public Object builtinProcessor(DataTree dataTree, Map<Long, Integer> sessions, long lastZxid, Object acc) throws IOException {
237+
if (commandLine.hasOption(OPT_JSON)) {
238+
printSnapshotJson(dataTree);
239+
} else {
240+
printDetails(dataTree, sessions, lastZxid);
178241
}
242+
return acc;
179243
}
180244

181-
private void printDetails(DataTree dataTree, Map<Long, Integer> sessions, long fileNameZxid) {
245+
public static <A> A applyToChildren(DataTree dataTree, String parentPath, Collection<String> childNames, Fold<A> fold, A acc) throws IOException {
246+
String sep = parentPath.equals("/") ? "" : "/";
247+
for (String childName : childNames) {
248+
String path = parentPath + sep + childName;
249+
acc = fold.apply(dataTree, path, acc);
250+
}
251+
return acc;
252+
}
253+
254+
private void printDetails(DataTree dataTree, Map<Long, Integer> sessions, long fileNameZxid) throws IOException {
182255
long dtZxid = printZnodeDetails(dataTree);
183256
printSessionDetails(dataTree, sessions);
184257
DataTree.ZxidDigest targetZxidDigest = dataTree.getDigestFromLoadedSnapshot();
@@ -189,19 +262,18 @@ private void printDetails(DataTree dataTree, Map<Long, Integer> sessions, long f
189262
System.out.println(String.format("----%nLast zxid: 0x%s", Long.toHexString(Math.max(fileNameZxid, dtZxid))));
190263
}
191264

192-
private long printZnodeDetails(DataTree dataTree) {
265+
private long printZnodeDetails(DataTree dataTree) throws IOException {
193266
System.out.println(String.format("ZNode Details (count=%d):", dataTree.getNodeCount()));
194267

195-
final long zxid = printZnode(dataTree, "/");
268+
final long zxid = printZnode(dataTree, "/", 0L);
196269
System.out.println("----");
197270
return zxid;
198271
}
199272

200-
private long printZnode(DataTree dataTree, String name) {
273+
private Long printZnode(DataTree dataTree, String name, Long zxid) throws IOException {
201274
System.out.println("----");
202275
DataNode n = dataTree.getNode(name);
203276
Set<String> children;
204-
long zxid;
205277
synchronized (n) { // keep findbugs happy
206278
System.out.println(name);
207279
printStat(n.stat);
@@ -232,10 +304,7 @@ private long printZnode(DataTree dataTree, String name) {
232304
}
233305
}
234306
if (children != null) {
235-
for (String child : children) {
236-
long cxid = printZnode(dataTree, name + (name.equals("/") ? "" : "/") + child);
237-
zxid = Math.max(zxid, cxid);
238-
}
307+
zxid = applyToChildren(dataTree, name, children, this::printZnode, zxid);
239308
}
240309
return zxid;
241310
}
@@ -259,15 +328,15 @@ private static String formatAclEntry(ACL aclEntry) {
259328
return b.toString();
260329
}
261330

262-
private void printSessionDetails(DataTree dataTree, Map<Long, Integer> sessions) {
331+
private static void printSessionDetails(DataTree dataTree, Map<Long, Integer> sessions) {
263332
System.out.println("Session Details (sid, timeout, ephemeralCount):");
264333
for (Map.Entry<Long, Integer> e : sessions.entrySet()) {
265334
long sid = e.getKey();
266335
System.out.println(String.format("%#016x, %d, %d", sid, e.getValue(), dataTree.getEphemerals(sid).size()));
267336
}
268337
}
269338

270-
private void printStat(StatPersisted stat) {
339+
private static void printStat(StatPersisted stat) {
271340
printHex("cZxid", stat.getCzxid());
272341
System.out.println(" ctime = " + new Date(stat.getCtime()).toString());
273342
printHex("mZxid", stat.getMzxid());
@@ -279,11 +348,11 @@ private void printStat(StatPersisted stat) {
279348
printHex("ephemeralOwner", stat.getEphemeralOwner());
280349
}
281350

282-
private void printHex(String prefix, long value) {
351+
private static void printHex(String prefix, long value) {
283352
System.out.println(String.format(" %s = %#016x", prefix, value));
284353
}
285354

286-
private void printSnapshotJson(final DataTree dataTree) {
355+
private static void printSnapshotJson(final DataTree dataTree) throws IOException {
287356
JsonStringEncoder encoder = JsonStringEncoder.getInstance();
288357
System.out.printf(
289358
"[1,0,{\"progname\":\"SnapshotFormatter.java\",\"progver\":\"0.01\",\"timestamp\":%d}",
@@ -292,14 +361,14 @@ private void printSnapshotJson(final DataTree dataTree) {
292361
System.out.print("]");
293362
}
294363

295-
private void printZnodeJson(final DataTree dataTree, final String fullPath, JsonStringEncoder encoder) {
364+
private static JsonStringEncoder printZnodeJson(final DataTree dataTree, final String fullPath, JsonStringEncoder encoder) throws IOException {
296365

297366

298367
final DataNode n = dataTree.getNode(fullPath);
299368

300369
if (null == n) {
301370
LOG.warn("DataTree Node for {} doesn't exist", fullPath);
302-
return;
371+
return encoder;
303372
}
304373

305374
final String name = fullPath.equals("/")
@@ -327,13 +396,11 @@ private void printZnodeJson(final DataTree dataTree, final String fullPath, Json
327396
}
328397
if (children != null && children.size() > 0) {
329398
System.out.print("[" + nodeSB);
330-
for (String child : children) {
331-
printZnodeJson(dataTree, fullPath + (fullPath.equals("/") ? "" : "/") + child, encoder);
332-
}
399+
encoder = applyToChildren(dataTree, fullPath, children, SnapshotFormatter::printZnodeJson, encoder);
333400
System.out.print("]");
334401
} else {
335402
System.out.print(nodeSB);
336403
}
404+
return encoder;
337405
}
338-
339406
}

0 commit comments

Comments
 (0)