|
@@ -18,53 +18,36 @@
|
|
|
|
|
|
package org.apache.zookeeper.server;
|
|
|
|
|
|
-import java.io.BufferedInputStream;
|
|
|
-import java.io.BufferedOutputStream;
|
|
|
-import java.io.ByteArrayInputStream;
|
|
|
import java.io.ByteArrayOutputStream;
|
|
|
-import java.io.EOFException;
|
|
|
import java.io.File;
|
|
|
-import java.io.FileInputStream;
|
|
|
-import java.io.FileOutputStream;
|
|
|
import java.io.IOException;
|
|
|
-import java.io.InputStream;
|
|
|
-import java.io.OutputStream;
|
|
|
-import java.io.RandomAccessFile;
|
|
|
import java.nio.ByteBuffer;
|
|
|
-import java.nio.channels.FileChannel;
|
|
|
import java.util.ArrayList;
|
|
|
import java.util.Arrays;
|
|
|
-import java.util.Collections;
|
|
|
-import java.util.Comparator;
|
|
|
-import java.util.HashMap;
|
|
|
import java.util.LinkedList;
|
|
|
import java.util.List;
|
|
|
import java.util.Random;
|
|
|
-import java.util.Map.Entry;
|
|
|
import java.util.concurrent.ConcurrentHashMap;
|
|
|
import java.util.concurrent.LinkedBlockingQueue;
|
|
|
|
|
|
-import org.apache.log4j.Logger;
|
|
|
-
|
|
|
import org.apache.jute.BinaryInputArchive;
|
|
|
import org.apache.jute.BinaryOutputArchive;
|
|
|
import org.apache.jute.InputArchive;
|
|
|
+import org.apache.jute.OutputArchive;
|
|
|
import org.apache.jute.Record;
|
|
|
+import org.apache.log4j.Logger;
|
|
|
import org.apache.zookeeper.ZooDefs.OpCode;
|
|
|
import org.apache.zookeeper.data.ACL;
|
|
|
import org.apache.zookeeper.data.Id;
|
|
|
import org.apache.zookeeper.data.Stat;
|
|
|
import org.apache.zookeeper.proto.RequestHeader;
|
|
|
import org.apache.zookeeper.server.SessionTracker.SessionExpirer;
|
|
|
+import org.apache.zookeeper.server.persistence.FileTxnSnapLog;
|
|
|
+import org.apache.zookeeper.server.persistence.FileTxnSnapLog.PlayBackListener;
|
|
|
import org.apache.zookeeper.server.quorum.Leader;
|
|
|
import org.apache.zookeeper.server.quorum.QuorumPacket;
|
|
|
import org.apache.zookeeper.server.quorum.Leader.Proposal;
|
|
|
-import org.apache.zookeeper.txn.CreateSessionTxn;
|
|
|
-import org.apache.zookeeper.txn.CreateTxn;
|
|
|
-import org.apache.zookeeper.txn.DeleteTxn;
|
|
|
-import org.apache.zookeeper.txn.ErrorTxn;
|
|
|
-import org.apache.zookeeper.txn.SetACLTxn;
|
|
|
-import org.apache.zookeeper.txn.SetDataTxn;
|
|
|
+import org.apache.zookeeper.server.util.SerializeUtils;
|
|
|
import org.apache.zookeeper.txn.TxnHeader;
|
|
|
|
|
|
/**
|
|
@@ -108,14 +91,7 @@ public class ZooKeeperServer implements SessionExpirer, ServerStats.Provider {
|
|
|
private DataTreeBuilder treeBuilder;
|
|
|
public DataTree dataTree;
|
|
|
protected SessionTracker sessionTracker;
|
|
|
- /**
|
|
|
- * directory for storing the snapshot
|
|
|
- */
|
|
|
- File dataDir;
|
|
|
- /**
|
|
|
- * directoy for storing the log tnxns
|
|
|
- */
|
|
|
- File dataLogDir;
|
|
|
+ private FileTxnSnapLog txnLogFactory = null;
|
|
|
protected ConcurrentHashMap<Long, Integer> sessionsWithTimeouts;
|
|
|
protected long hzxid = 0;
|
|
|
final public static Exception ok = new Exception("No prob");
|
|
@@ -131,12 +107,12 @@ public class ZooKeeperServer implements SessionExpirer, ServerStats.Provider {
|
|
|
List<ChangeRecord> outstandingChanges = new ArrayList<ChangeRecord>();
|
|
|
private NIOServerCnxn.Factory serverCnxnFactory;
|
|
|
private int clientPort;
|
|
|
-
|
|
|
-
|
|
|
+
|
|
|
void removeCnxn(ServerCnxn cnxn) {
|
|
|
dataTree.removeCnxn(cnxn);
|
|
|
}
|
|
|
|
|
|
+
|
|
|
/**
|
|
|
* Creates a ZooKeeperServer instance. Nothing is setup, use the setX
|
|
|
* methods to prepare the instance (eg datadir, datalogdir, ticktime,
|
|
@@ -148,6 +124,8 @@ public class ZooKeeperServer implements SessionExpirer, ServerStats.Provider {
|
|
|
ServerStats.getInstance().setStatsProvider(this);
|
|
|
treeBuilder = new BasicDataTreeBuilder();
|
|
|
}
|
|
|
+
|
|
|
+
|
|
|
/**
|
|
|
* Creates a ZooKeeperServer instance. It sets everything up, but doesn't
|
|
|
* actually start listening for clients until run() is invoked.
|
|
@@ -155,27 +133,25 @@ public class ZooKeeperServer implements SessionExpirer, ServerStats.Provider {
|
|
|
* @param dataDir the directory to put the data
|
|
|
* @throws IOException
|
|
|
*/
|
|
|
- public ZooKeeperServer(File dataDir, File dataLogDir, int tickTime,
|
|
|
+ public ZooKeeperServer(FileTxnSnapLog txnLogFactory, int tickTime,
|
|
|
DataTreeBuilder treeBuilder) throws IOException {
|
|
|
- this.dataDir = dataDir;
|
|
|
- this.dataLogDir = dataLogDir;
|
|
|
+ this.txnLogFactory=txnLogFactory;
|
|
|
this.tickTime = tickTime;
|
|
|
this.treeBuilder = treeBuilder;
|
|
|
ServerStats.getInstance().setStatsProvider(this);
|
|
|
|
|
|
- LOG.info("Created server with dataDir:" + dataDir
|
|
|
- + " dataLogDir:" + dataLogDir
|
|
|
- + " tickTime:" + tickTime);
|
|
|
+ LOG.info("Created server");
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* This constructor is for backward compatibility with the existing unit
|
|
|
* test code.
|
|
|
+ * It defaults to FileLogProvider persistence provider.
|
|
|
*/
|
|
|
- public ZooKeeperServer(File dataDir, File dataLogDir, int tickTime)
|
|
|
- throws IOException
|
|
|
- {
|
|
|
- this(dataDir, dataLogDir, tickTime, new BasicDataTreeBuilder());
|
|
|
+ public ZooKeeperServer(File snapDir, File logDir, int tickTime)
|
|
|
+ throws IOException {
|
|
|
+ this(new FileTxnSnapLog(snapDir,logDir),
|
|
|
+ tickTime,new BasicDataTreeBuilder());
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -183,180 +159,28 @@ public class ZooKeeperServer implements SessionExpirer, ServerStats.Provider {
|
|
|
*
|
|
|
* @throws IOException
|
|
|
*/
|
|
|
- public ZooKeeperServer(DataTreeBuilder treeBuilder) throws IOException {
|
|
|
- this(new File(ServerConfig.getDataDir()), new File(ServerConfig
|
|
|
- .getDataLogDir()), DEFAULT_TICK_TIME, treeBuilder);
|
|
|
- }
|
|
|
-
|
|
|
- public static long getZxidFromName(String name, String prefix) {
|
|
|
- long zxid = -1;
|
|
|
- String nameParts[] = name.split("\\.");
|
|
|
- if (nameParts.length == 2 && nameParts[0].equals(prefix)) {
|
|
|
- try {
|
|
|
- zxid = Long.parseLong(nameParts[1], 16);
|
|
|
- } catch (NumberFormatException e) {
|
|
|
- LOG.warn("unable to parse zxid string into long: "
|
|
|
- + nameParts[1]);
|
|
|
- }
|
|
|
- }
|
|
|
- return zxid;
|
|
|
- }
|
|
|
-
|
|
|
- static public long isValidSnapshot(File f) throws IOException {
|
|
|
- long zxid = getZxidFromName(f.getName(), "snapshot");
|
|
|
- if (zxid == -1)
|
|
|
- return -1;
|
|
|
-
|
|
|
- // Check for a valid snapshot
|
|
|
- RandomAccessFile raf = new RandomAccessFile(f, "r");
|
|
|
- try {
|
|
|
- raf.seek(raf.length() - 5);
|
|
|
- byte bytes[] = new byte[5];
|
|
|
- raf.read(bytes);
|
|
|
- ByteBuffer bb = ByteBuffer.wrap(bytes);
|
|
|
- int len = bb.getInt();
|
|
|
- byte b = bb.get();
|
|
|
- if (len != 1 || b != '/') {
|
|
|
- LOG.warn("Invalid snapshot " + f + " len = " + len
|
|
|
- + " byte = " + (b & 0xff));
|
|
|
- return -1;
|
|
|
- }
|
|
|
- } finally {
|
|
|
- raf.close();
|
|
|
- }
|
|
|
-
|
|
|
- return zxid;
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * Compare file file names of form "prefix.version". Sort order result
|
|
|
- * returned in order of version.
|
|
|
- */
|
|
|
- private static class DataDirFileComparator implements Comparator<File> {
|
|
|
- private String prefix;
|
|
|
- private boolean ascending;
|
|
|
- public DataDirFileComparator(String prefix, boolean ascending) {
|
|
|
- this.prefix = prefix;
|
|
|
- this.ascending = ascending;
|
|
|
- }
|
|
|
-
|
|
|
- public int compare(File o1, File o2) {
|
|
|
- long z1 = getZxidFromName(o1.getName(), prefix);
|
|
|
- long z2 = getZxidFromName(o2.getName(), prefix);
|
|
|
- int result = z1 < z2 ? -1 : (z1 > z2 ? 1 : 0);
|
|
|
- return ascending ? result : -result;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * Sort the list of files. Recency as determined by the version component
|
|
|
- * of the file name.
|
|
|
- *
|
|
|
- * @param files array of files
|
|
|
- * @param prefix files not matching this prefix are assumed to have a
|
|
|
- * version = -1)
|
|
|
- * @param ascending true sorted in ascending order, false results in
|
|
|
- * descending order
|
|
|
- * @return sorted input files
|
|
|
- */
|
|
|
- static List<File>
|
|
|
- sortDataDir(File[] files, String prefix, boolean ascending)
|
|
|
- {
|
|
|
- List<File> filelist = Arrays.asList(files);
|
|
|
- Collections.sort(filelist, new DataDirFileComparator(prefix, ascending));
|
|
|
- return filelist;
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * Find the log file that starts at, or just before, the snapshot. Return
|
|
|
- * this and all subsequent logs. Results are ordered by zxid of file,
|
|
|
- * ascending order.
|
|
|
- *
|
|
|
- * @param logDirList array of files
|
|
|
- * @param snapshotZxid return files at, or before this zxid
|
|
|
- * @return
|
|
|
- */
|
|
|
- static File[] getLogFiles(File[] logDirList,long snapshotZxid) {
|
|
|
- List<File> files = sortDataDir(logDirList, "log", true);
|
|
|
- long logZxid = 0;
|
|
|
- // Find the log file that starts before or at the same time as the
|
|
|
- // zxid of the snapshot
|
|
|
- for (File f : files) {
|
|
|
- long fzxid = getZxidFromName(f.getName(), "log");
|
|
|
- if (fzxid > snapshotZxid) {
|
|
|
- continue;
|
|
|
- }
|
|
|
- if (fzxid > logZxid) {
|
|
|
- logZxid = fzxid;
|
|
|
- }
|
|
|
- }
|
|
|
- List<File> v=new ArrayList<File>(5);
|
|
|
- // Apply the logs
|
|
|
- for (File f : files) {
|
|
|
- long fzxid = getZxidFromName(f.getName(), "log");
|
|
|
- if (fzxid < logZxid) {
|
|
|
- continue;
|
|
|
- }
|
|
|
- v.add(f);
|
|
|
- }
|
|
|
- return v.toArray(new File[0]);
|
|
|
+ public ZooKeeperServer(FileTxnSnapLog txnLogFactory,DataTreeBuilder treeBuilder) throws IOException {
|
|
|
+ this(txnLogFactory, DEFAULT_TICK_TIME, treeBuilder);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Restore sessions and data
|
|
|
*/
|
|
|
- private void loadSnapshotAndLogs() throws IOException {
|
|
|
- long zxid = -1;
|
|
|
-
|
|
|
- // Find the most recent snapshot
|
|
|
- List<File> files = sortDataDir(dataDir.listFiles(), "snapshot", false);
|
|
|
- for (File f : files) {
|
|
|
- zxid = isValidSnapshot(f);
|
|
|
- if (zxid == -1) {
|
|
|
- LOG.warn("Skipping " + f);
|
|
|
- continue;
|
|
|
- }
|
|
|
-
|
|
|
- LOG.warn("Processing snapshot: " + f);
|
|
|
-
|
|
|
- FileInputStream snapFIS = new FileInputStream(f);
|
|
|
- try {
|
|
|
- InputStream snapIS = new BufferedInputStream(snapFIS);
|
|
|
- try {
|
|
|
- loadData(BinaryInputArchive.getArchive(snapIS));
|
|
|
- } finally {
|
|
|
- snapIS.close();
|
|
|
- }
|
|
|
- } finally {
|
|
|
- snapFIS.close();
|
|
|
- }
|
|
|
-
|
|
|
- dataTree.lastProcessedZxid = zxid;
|
|
|
-
|
|
|
- // Apply the logs on/after the selected snapshot
|
|
|
- File[] logfiles = getLogFiles(dataLogDir.listFiles(), zxid);
|
|
|
- for (File logfile : logfiles) {
|
|
|
- LOG.warn("Processing log file: " + logfile);
|
|
|
-
|
|
|
- InputStream logIS =
|
|
|
- new BufferedInputStream(new FileInputStream(logfile));
|
|
|
- zxid = playLog(BinaryInputArchive.getArchive(logIS));
|
|
|
- logIS.close();
|
|
|
- }
|
|
|
- hzxid = zxid;
|
|
|
-
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- if (zxid == -1) {
|
|
|
- sessionsWithTimeouts = new ConcurrentHashMap<Long, Integer>();
|
|
|
- dataTree = treeBuilder.build();
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
public void loadData() throws IOException, InterruptedException {
|
|
|
- loadSnapshotAndLogs();
|
|
|
-
|
|
|
+ PlayBackListener listener=new PlayBackListener(){
|
|
|
+ public void onTxnLoaded(TxnHeader hdr,Record txn){
|
|
|
+ Request r = new Request(null, 0, hdr.getCxid(),hdr.getType(),
|
|
|
+ null, null);
|
|
|
+ r.txn = txn;
|
|
|
+ r.hdr = hdr;
|
|
|
+ r.zxid = hdr.getZxid();
|
|
|
+ addCommittedProposal(r);
|
|
|
+ }
|
|
|
+ };
|
|
|
+ sessionsWithTimeouts = new ConcurrentHashMap<Long, Integer>();
|
|
|
+ dataTree = treeBuilder.build();
|
|
|
+ long zxid = txnLogFactory.restore(dataTree,sessionsWithTimeouts,listener);
|
|
|
+ this.hzxid = zxid;
|
|
|
// Clean up dead sessions
|
|
|
LinkedList<Long> deadSessions = new LinkedList<Long>();
|
|
|
for (long session : dataTree.getSessions()) {
|
|
@@ -369,94 +193,14 @@ public class ZooKeeperServer implements SessionExpirer, ServerStats.Provider {
|
|
|
killSession(session);
|
|
|
}
|
|
|
// Make a clean snapshot
|
|
|
- snapshot();
|
|
|
- }
|
|
|
-
|
|
|
- public void loadData(InputArchive ia) throws IOException {
|
|
|
- sessionsWithTimeouts = new ConcurrentHashMap<Long, Integer>();
|
|
|
- dataTree = treeBuilder.build();
|
|
|
-
|
|
|
- int count = ia.readInt("count");
|
|
|
- while (count > 0) {
|
|
|
- long id = ia.readLong("id");
|
|
|
- int to = ia.readInt("timeout");
|
|
|
- sessionsWithTimeouts.put(id, to);
|
|
|
- ZooTrace.logTraceMessage(LOG, ZooTrace.SESSION_TRACE_MASK,
|
|
|
- "loadData --- session in archive: " + id
|
|
|
- + " with timeout: " + to);
|
|
|
- count--;
|
|
|
- }
|
|
|
- dataTree.deserialize(ia, "tree");
|
|
|
- }
|
|
|
-
|
|
|
- public long playLog(InputArchive logStream) throws IOException {
|
|
|
- long highestZxid = 0;
|
|
|
- try {
|
|
|
- while (true) {
|
|
|
- byte[] bytes = logStream.readBuffer("txnEntry");
|
|
|
- if (bytes.length == 0) {
|
|
|
- // Since we preallocate, we define EOF to be an
|
|
|
- // empty transaction
|
|
|
- throw new EOFException();
|
|
|
- }
|
|
|
- InputArchive ia = BinaryInputArchive
|
|
|
- .getArchive(new ByteArrayInputStream(bytes));
|
|
|
- TxnHeader hdr = new TxnHeader();
|
|
|
- Record txn = deserializeTxn(ia, hdr);
|
|
|
- if (logStream.readByte("EOR") != 'B') {
|
|
|
- LOG.warn("Last transaction was partial.");
|
|
|
- throw new EOFException();
|
|
|
- }
|
|
|
- if (hdr.getZxid() <= highestZxid && highestZxid != 0) {
|
|
|
- LOG.error(highestZxid + "(higestZxid) >= "
|
|
|
- + hdr.getZxid() + "(next log) for type "
|
|
|
- + hdr.getType());
|
|
|
- } else {
|
|
|
- highestZxid = hdr.getZxid();
|
|
|
- }
|
|
|
- switch (hdr.getType()) {
|
|
|
- case OpCode.createSession:
|
|
|
- sessionsWithTimeouts.put(hdr.getClientId(),
|
|
|
- ((CreateSessionTxn) txn).getTimeOut());
|
|
|
- ZooTrace.logTraceMessage(LOG,
|
|
|
- ZooTrace.SESSION_TRACE_MASK,
|
|
|
- "playLog --- create session in log: 0x"
|
|
|
- + Long.toHexString(hdr.getClientId())
|
|
|
- + " with timeout: "
|
|
|
- + ((CreateSessionTxn) txn).getTimeOut());
|
|
|
- // give dataTree a chance to sync its lastProcessedZxid
|
|
|
- dataTree.processTxn(hdr, txn);
|
|
|
- break;
|
|
|
- case OpCode.closeSession:
|
|
|
- sessionsWithTimeouts.remove(hdr.getClientId());
|
|
|
- ZooTrace.logTraceMessage(LOG,
|
|
|
- ZooTrace.SESSION_TRACE_MASK,
|
|
|
- "playLog --- close session in log: 0x"
|
|
|
- + Long.toHexString(hdr.getClientId()));
|
|
|
- dataTree.processTxn(hdr, txn);
|
|
|
- break;
|
|
|
- default:
|
|
|
- dataTree.processTxn(hdr, txn);
|
|
|
- }
|
|
|
- Request r = new Request(null, 0, hdr.getCxid(), hdr.getType(),
|
|
|
- null, null);
|
|
|
- r.txn = txn;
|
|
|
- r.hdr = hdr;
|
|
|
- r.zxid = hdr.getZxid();
|
|
|
- addCommittedProposal(r);
|
|
|
- }
|
|
|
- } catch (EOFException e) {
|
|
|
- // expected in some cases - see comments in try block
|
|
|
- }
|
|
|
- return highestZxid;
|
|
|
+ takeSnapshot();
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* maintains a list of last 500 or so committed requests. This is used for
|
|
|
* fast follower synchronization.
|
|
|
*
|
|
|
- * @param request
|
|
|
- * committed request
|
|
|
+ * @param request committed request
|
|
|
*/
|
|
|
|
|
|
public void addCommittedProposal(Request request) {
|
|
@@ -492,135 +236,9 @@ public class ZooKeeperServer implements SessionExpirer, ServerStats.Provider {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- static public Record deserializeTxn(InputArchive ia, TxnHeader hdr)
|
|
|
- throws IOException {
|
|
|
- hdr.deserialize(ia, "hdr");
|
|
|
- Record txn = null;
|
|
|
- switch (hdr.getType()) {
|
|
|
- case OpCode.createSession:
|
|
|
- // This isn't really an error txn; it just has the same
|
|
|
- // format. The error represents the timeout
|
|
|
- txn = new CreateSessionTxn();
|
|
|
- break;
|
|
|
- case OpCode.closeSession:
|
|
|
- return null;
|
|
|
- case OpCode.create:
|
|
|
- txn = new CreateTxn();
|
|
|
- break;
|
|
|
- case OpCode.delete:
|
|
|
- txn = new DeleteTxn();
|
|
|
- break;
|
|
|
- case OpCode.setData:
|
|
|
- txn = new SetDataTxn();
|
|
|
- break;
|
|
|
- case OpCode.setACL:
|
|
|
- txn = new SetACLTxn();
|
|
|
- break;
|
|
|
- case OpCode.error:
|
|
|
- txn = new ErrorTxn();
|
|
|
- break;
|
|
|
- }
|
|
|
- if (txn != null) {
|
|
|
- txn.deserialize(ia, "txn");
|
|
|
- }
|
|
|
- return txn;
|
|
|
- }
|
|
|
-
|
|
|
- public void truncateLog(long finalZxid) throws IOException {
|
|
|
- long highestZxid = 0;
|
|
|
- for (File f : dataDir.listFiles()) {
|
|
|
- long zxid = isValidSnapshot(f);
|
|
|
- if (zxid == -1) {
|
|
|
- LOG.warn("Skipping " + f);
|
|
|
- continue;
|
|
|
- }
|
|
|
- if (zxid > highestZxid) {
|
|
|
- highestZxid = zxid;
|
|
|
- }
|
|
|
- }
|
|
|
- File[] files = getLogFiles(dataLogDir.listFiles(), highestZxid);
|
|
|
- boolean truncated = false;
|
|
|
- for (File f : files) {
|
|
|
- FileInputStream fin = new FileInputStream(f);
|
|
|
- InputArchive ia = BinaryInputArchive.getArchive(fin);
|
|
|
- FileChannel fchan = fin.getChannel();
|
|
|
- try {
|
|
|
- while (true) {
|
|
|
- byte[] bytes = ia.readBuffer("txtEntry");
|
|
|
- if (bytes.length == 0) {
|
|
|
- // Since we preallocate, we define EOF to be an
|
|
|
- // empty transaction
|
|
|
- throw new EOFException();
|
|
|
- }
|
|
|
- InputArchive iab = BinaryInputArchive
|
|
|
- .getArchive(new ByteArrayInputStream(bytes));
|
|
|
- TxnHeader hdr = new TxnHeader();
|
|
|
- deserializeTxn(iab, hdr);
|
|
|
- if (ia.readByte("EOF") != 'B') {
|
|
|
- LOG.warn("Last transaction was partial.");
|
|
|
- throw new EOFException();
|
|
|
- }
|
|
|
- if (hdr.getZxid() == finalZxid) {
|
|
|
- // this is where we need to truncate
|
|
|
-
|
|
|
- long pos = fchan.position();
|
|
|
- fin.close();
|
|
|
- FileOutputStream fout = new FileOutputStream(f);
|
|
|
- FileChannel fchanOut = fout.getChannel();
|
|
|
- fchanOut.truncate(pos);
|
|
|
- fchanOut.close();
|
|
|
- fout.close();
|
|
|
- truncated = true;
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
- } catch (EOFException eof) {
|
|
|
- // expected in some cases - see comments in try block
|
|
|
- } finally {
|
|
|
- fchan.close();
|
|
|
- fin.close();
|
|
|
- }
|
|
|
- if (truncated == true) {
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
- if (truncated == false) {
|
|
|
- // not able to truncate the log
|
|
|
- LOG.error("Not able to truncate the log zxid 0x"
|
|
|
- + Long.toHexString(finalZxid));
|
|
|
- System.exit(13);
|
|
|
- }
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- public void snapshot(BinaryOutputArchive oa) throws IOException,
|
|
|
- InterruptedException {
|
|
|
- HashMap<Long, Integer> sessSnap = new HashMap<Long, Integer>(
|
|
|
- sessionsWithTimeouts);
|
|
|
- oa.writeInt(sessSnap.size(), "count");
|
|
|
- for (Entry<Long, Integer> entry : sessSnap.entrySet()) {
|
|
|
- oa.writeLong(entry.getKey().longValue(), "id");
|
|
|
- oa.writeInt(entry.getValue().intValue(), "timeout");
|
|
|
- }
|
|
|
- dataTree.serialize(oa, "tree");
|
|
|
- }
|
|
|
-
|
|
|
- public void snapshot() throws InterruptedException {
|
|
|
- long lastZxid = dataTree.lastProcessedZxid;
|
|
|
- ZooTrace.logTraceMessage(LOG, ZooTrace.getTextTraceLevel(),
|
|
|
- "Snapshotting: zxid 0x" + Long.toHexString(lastZxid));
|
|
|
+ public void takeSnapshot(){
|
|
|
try {
|
|
|
- File f = new File(dataDir, "snapshot." + Long.toHexString(lastZxid));
|
|
|
- OutputStream sessOS = new BufferedOutputStream(new FileOutputStream(f));
|
|
|
- try {
|
|
|
- BinaryOutputArchive oa = BinaryOutputArchive.getArchive(sessOS);
|
|
|
- snapshot(oa);
|
|
|
- sessOS.flush();
|
|
|
- } finally {
|
|
|
- sessOS.close();
|
|
|
- }
|
|
|
- ZooTrace.logTraceMessage(LOG, ZooTrace.getTextTraceLevel(),
|
|
|
- "Snapshotting finished: zxid 0x" + Long.toHexString(lastZxid));
|
|
|
+ txnLogFactory.save(dataTree, sessionsWithTimeouts);
|
|
|
} catch (IOException e) {
|
|
|
LOG.error("Severe error, exiting",e);
|
|
|
// This is a severe error that we cannot recover from,
|
|
@@ -629,6 +247,18 @@ public class ZooKeeperServer implements SessionExpirer, ServerStats.Provider {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ public void serializeSnapshot(OutputArchive oa) throws IOException,
|
|
|
+ InterruptedException {
|
|
|
+ SerializeUtils.serializeSnapshot(dataTree, oa, sessionsWithTimeouts);
|
|
|
+ }
|
|
|
+
|
|
|
+ public void deserializeSnapshot(InputArchive ia) throws IOException {
|
|
|
+ sessionsWithTimeouts = new ConcurrentHashMap<Long, Integer>();
|
|
|
+ dataTree = treeBuilder.build();
|
|
|
+
|
|
|
+ SerializeUtils.deserializeSnapshot(dataTree,ia,sessionsWithTimeouts);
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
* This should be called from a synchronized block on this!
|
|
|
*/
|
|
@@ -644,10 +274,6 @@ public class ZooKeeperServer implements SessionExpirer, ServerStats.Provider {
|
|
|
return System.currentTimeMillis();
|
|
|
}
|
|
|
|
|
|
- static String getLogName(long zxid) {
|
|
|
- return "log." + Long.toHexString(zxid);
|
|
|
- }
|
|
|
-
|
|
|
public void closeSession(long sessionId) throws InterruptedException {
|
|
|
ZooTrace.logTraceMessage(LOG, ZooTrace.SESSION_TRACE_MASK,
|
|
|
"ZooKeeperServer --- Session to be closed: 0x"
|
|
@@ -691,14 +317,6 @@ public class ZooKeeperServer implements SessionExpirer, ServerStats.Provider {
|
|
|
}
|
|
|
|
|
|
public void startup() throws IOException, InterruptedException {
|
|
|
- if (dataDir == null || !dataDir.isDirectory()) {
|
|
|
- throw new IOException("data directory does not exist: " + dataDir);
|
|
|
- }
|
|
|
- if (dataLogDir == null || !dataLogDir.isDirectory()) {
|
|
|
- throw new IOException("data log directory does not exist: "
|
|
|
- + dataLogDir);
|
|
|
- }
|
|
|
-
|
|
|
if (dataTree == null) {
|
|
|
loadData();
|
|
|
}
|
|
@@ -916,14 +534,42 @@ public class ZooKeeperServer implements SessionExpirer, ServerStats.Provider {
|
|
|
return serverCnxnFactory;
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * return the last proceesed id from the
|
|
|
+ * datatree
|
|
|
+ */
|
|
|
public long getLastProcessedZxid() {
|
|
|
return dataTree.lastProcessedZxid;
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * return the outstanding requests
|
|
|
+ * in the queue, which havent been
|
|
|
+ * processed yet
|
|
|
+ */
|
|
|
public long getOutstandingRequests() {
|
|
|
return getInProcess();
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * trunccate the log to get in sync with others
|
|
|
+ * if in a quorum
|
|
|
+ * @param zxid the zxid that it needs to get in sync
|
|
|
+ * with others
|
|
|
+ * @throws IOException
|
|
|
+ */
|
|
|
+ public void truncateLog(long zxid) throws IOException {
|
|
|
+ this.txnLogFactory.truncateLog(zxid);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * the snapshot and logwriter for this instance
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public FileTxnSnapLog getLogWriter() {
|
|
|
+ return this.txnLogFactory;
|
|
|
+ }
|
|
|
+
|
|
|
public int getTickTime() {
|
|
|
return tickTime;
|
|
|
}
|
|
@@ -939,41 +585,7 @@ public class ZooKeeperServer implements SessionExpirer, ServerStats.Provider {
|
|
|
public void setTreeBuilder(DataTreeBuilder treeBuilder) {
|
|
|
this.treeBuilder = treeBuilder;
|
|
|
}
|
|
|
-
|
|
|
- /**
|
|
|
- * Gets directory for storing the snapshot
|
|
|
- */
|
|
|
- public File getDataDir() {
|
|
|
- return dataDir;
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * Sets directory for storing the snapshot
|
|
|
- */
|
|
|
- public void setDataDir(File dataDir) throws IOException {
|
|
|
- this.dataDir = dataDir;
|
|
|
- if (!dataDir.isDirectory()) {
|
|
|
- throw new IOException("data directory does not exist");
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * Gets directoy for storing the log tnxns
|
|
|
- */
|
|
|
- public File getDataLogDir() {
|
|
|
- return dataLogDir;
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * Sets directoy for storing the log tnxns
|
|
|
- */
|
|
|
- public void setDataLogDir(File dataLogDir) throws IOException {
|
|
|
- this.dataLogDir = dataLogDir;
|
|
|
- if (!dataLogDir.isDirectory()) {
|
|
|
- throw new IOException("data log directory does not exist");
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
+
|
|
|
public int getClientPort() {
|
|
|
return clientPort;
|
|
|
}
|
|
@@ -981,4 +593,12 @@ public class ZooKeeperServer implements SessionExpirer, ServerStats.Provider {
|
|
|
public void setClientPort(int clientPort) {
|
|
|
this.clientPort = clientPort;
|
|
|
}
|
|
|
+
|
|
|
+ public void setTxnLogFactory(FileTxnSnapLog txnLog) {
|
|
|
+ this.txnLogFactory = txnLog;
|
|
|
+ }
|
|
|
+
|
|
|
+ public FileTxnSnapLog getTxnLogFactory() {
|
|
|
+ return this.txnLogFactory;
|
|
|
+ }
|
|
|
}
|