zk中的事务日志

僤鯓⒐⒋嵵緔 提交于 2019-11-30 11:58:11
zk事务日志文件用来标记事务操作,每一个事务操作如添加,删除节点等等 都会在事务日志中记录一条记录,用来在zookeeper异常情况下恢复数据 public interface TxnLog extends Closeable { /** * Setter for ServerStats to monitor fsync threshold exceed * 设置服务状态 * @param serverStats used to update fsyncThresholdExceedCount */ void setServerStats(ServerStats serverStats); /** * roll the current * 将前添加日志滚动 * log being appended to * @throws IOException */ void rollLog() throws IOException; /** * Append a request to the transaction log * 添加请求 * @param hdr the transaction header * @param r the transaction itself * @return true iff something appended, otw false * @throws IOException */ boolean append(TxnHeader hdr, Record r) throws IOException; /** * Start reading the transaction logs * 开始读事务日志 * from a given zxid * @param zxid * @return returns an iterator to read the * next transaction in the logs. * @throws IOException */ TxnIterator read(long zxid) throws IOException; /** * the last zxid of the logged transactions. * 最后一个记录的事务日志id * @return the last zxid of the logged transactions. * @throws IOException */ long getLastLoggedZxid() throws IOException; /** * truncate the log to get in sync with the * leader. * @param zxid the zxid to truncate at. * @throws IOException */ boolean truncate(long zxid) throws IOException; /** * the dbid for this transaction log. * @return the dbid for this transaction log. * @throws IOException */ long getDbId() throws IOException; /** * commit the transaction and make sure * 提交 * they are persisted * @throws IOException */ void commit() throws IOException; /** * * @return transaction log's elapsed sync time in milliseconds */ long getTxnLogSyncElapsedTime(); /** * Sets the total size of all log files */ void setTotalLogSize(long size); /** * Gets the total size of all log files */ long getTotalLogSize(); /** * an iterating interface for reading * transaction logs. */ interface TxnIterator extends Closeable { /** * return the transaction header. * @return return the transaction header. */ TxnHeader getHeader(); /** * return the transaction record. * @return return the transaction record. */ Record getTxn(); /** * go to the next transaction record. * @throws IOException */ boolean next() throws IOException; /** * Get an estimated storage space used to store transaction records * that will return by this iterator * @throws IOException */ long getStorageSize() throws IOException; } } 实现类主要方法,append: /** * append an entry to the transaction log * @param hdr the header of the transaction * @param txn the transaction part of the entry * returns true iff something appended, otw false */ public synchronized boolean append(TxnHeader hdr, Record txn) throws IOException { if (hdr == null) { return false; } if (hdr.getZxid() <= lastZxidSeen) { LOG.warn("Current zxid " + hdr.getZxid() + " is <= " + lastZxidSeen + " for " + hdr.getType()); } else { lastZxidSeen = hdr.getZxid(); } if (logStream == null) { if (LOG.isInfoEnabled()) { LOG.info("Creating new log file: " + Util.makeLogName(hdr.getZxid())); } logFileWrite = new File(logDir, Util.makeLogName(hdr.getZxid())); fos = new FileOutputStream(logFileWrite); //日志流 logStream = new BufferedOutputStream(fos); oa = BinaryOutputArchive.getArchive(logStream); FileHeader fhdr = new FileHeader(TXNLOG_MAGIC, VERSION, dbId); fhdr.serialize(oa, "fileheader"); // Make sure that the magic number is written before padding. logStream.flush(); filePadding.setCurrentSize(fos.getChannel().position()); streamsToFlush.add(fos); } filePadding.padFile(fos.getChannel()); byte[] buf = Util.marshallTxnEntry(hdr, txn); if (buf == null || buf.length == 0) { throw new IOException("Faulty serialization for header " + "and txn"); } Checksum crc = makeChecksumAlgorithm(); crc.update(buf, 0, buf.length); oa.writeLong(crc.getValue(), "txnEntryCRC"); //写入字节流 Util.writeTxnBytes(oa, buf); return true; } /** * 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 返回指定snapshotZxid的LogFile */ public static File[] getLogFiles(File[] logDirList, long snapshotZxid) { List files = Util.sortDataDir(logDirList, LOG_FILE_PREFIX, 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 = Util.getZxidFromName(f.getName(), LOG_FILE_PREFIX); if (fzxid > snapshotZxid) { break; } // the files // are sorted with zxid's if (fzxid > logZxid) { logZxid = fzxid; } } List v = new ArrayList(5); for (File f : files) { long fzxid = Util.getZxidFromName(f.getName(), LOG_FILE_PREFIX); if (fzxid < logZxid) { continue; } v.add(f); } return v.toArray(new File[0]); } /** 获得最新事务日志zxid * get the last zxid that was logged in the transaction logs * @return the last zxid logged in the transaction logs */ public long getLastLoggedZxid() { File[] files = getLogFiles(logDir.listFiles(), 0); long maxLog = files.length > 0 ? Util.getZxidFromName(files[files.length - 1].getName(), LOG_FILE_PREFIX) : -1; // if a log file is more recent we must scan it to find // the highest zxid long zxid = maxLog; TxnIterator itr = null; try { FileTxnLog txn = new FileTxnLog(logDir); itr = txn.read(maxLog); while (true) { if (!itr.next()) { break; } TxnHeader hdr = itr.getHeader(); zxid = hdr.getZxid(); } } catch (IOException e) { LOG.warn("Unexpected exception", e); } finally { close(itr); } return zxid; } /** * commit the logs. make sure that everything hits the * disk 提交日志,确保持久化 */ public synchronized void commit() throws IOException { if (logStream != null) { logStream.flush(); } for (FileOutputStream log : streamsToFlush) { log.flush(); if (forceSync) { long startSyncNS = System.nanoTime(); FileChannel channel = log.getChannel(); channel.force(false); syncElapsedMS = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startSyncNS); if (syncElapsedMS > fsyncWarningThresholdMS) { if (serverStats != null) { serverStats.incrementFsyncThresholdExceedCount(); } LOG.warn("fsync-ing the write ahead log in " + Thread.currentThread().getName() + " took " + syncElapsedMS + "ms which will adversely effect operation latency. " + "File size is " + channel.size() + " bytes. " + "See the ZooKeeper troubleshooting guide"); } ServerMetrics.getMetrics().FSYNC_TIME.add(syncElapsedMS); } } while (streamsToFlush.size() > 1) { streamsToFlush.poll().close(); } // Roll the log file if we exceed the size limit if (txnLogSizeLimit > 0) { long logSize = getCurrentLogSize(); if (logSize > txnLogSizeLimit) { LOG.debug("Log size limit reached: {}", logSize); rollLog(); } } } /** * truncate the current transaction logs * @param zxid the zxid to truncate the logs to * @return true if successful false if not */ public boolean truncate(long zxid) throws IOException { FileTxnIterator itr = null; try { itr = new FileTxnIterator(this.logDir, zxid); PositionInputStream input = itr.inputStream; if (input == null) { throw new IOException("No log files found to truncate! This could " + "happen if you still have snapshots from an old setup or " + "log files were deleted accidentally or dataLogDir was changed in zoo.cfg."); } long pos = input.getPosition(); // now, truncate at the current position RandomAccessFile raf = new RandomAccessFile(itr.logFile, "rw"); raf.setLength(pos); raf.close(); while (itr.goToNextLog()) { if (!itr.logFile.delete()) { LOG.warn("Unable to truncate {}", itr.logFile); } } } finally { close(itr); } return true; } rollLog和commit的差异 什么时候会rollLog? 什么时候会truncate(long zxid) 什么时候会commit()
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!