交流
商城
MCN
登入
注册
首页
提问
分享
讨论
建议
公告
动态
发表新帖
发表新帖
第4-3 章:快照与日志
分享
未结
0
894
李延
LV6
2021-09-08
悬赏:20积分
# 1. 代码位置  # 2. SnapShot 快照接口。主要定义了两个方法 ```java //反序列化,将快照数据加载到内存中 long deserialize(DataTree dt, Map<Long, Integer> sessions) throws IOException; //序列化接口,将内存数据保存到本地文件中 void serialize(DataTree dt, Map<Long, Integer> sessions, File name, boolean fsync) throws IOException; ``` ## 2.1 实现:FileSnap FileSnap 为SnapShot 接口的唯一实现。我们先看一下序列化接口 ```java public synchronized void serialize( DataTree dt, Map<Long, Integer> sessions, File snapShot, boolean fsync) throws IOException { if (!close) { //创建文件输出流 try (CheckedOutputStream snapOS = SnapStream.getOutputStream(snapShot, fsync)) { //根据输出流创建OutputArchive对象 OutputArchive oa = BinaryOutputArchive.getArchive(snapOS); //创建文件头的序列化对象,并进行序列化 FileHeader header = new FileHeader(SNAP_MAGIC, VERSION, dbId); //序列化文件内容 serialize(dt, sessions, oa, header); //序列化校验码 SnapStream.sealStream(snapOS, oa); // Digest feature was added after the CRC to make it backward // compatible, the older code cal still read snapshots which // includes digest. // // To check the intact, after adding digest we added another // CRC check. //序列化zxid相关内容 if (dt.serializeZxidDigest(oa)) { SnapStream.sealStream(snapOS, oa); } //修改lastSnapshotInfo lastSnapshotInfo = new SnapshotInfo( Util.getZxidFromName(snapShot.getName(), SNAPSHOT_FILE_PREFIX), snapShot.lastModified() / 1000); } } else { throw new IOException("FileSnap has already been closed"); } } ``` 在上面代码中我们看到首先创建了对于文件的输出流和文件头的序列化类FileHeader对象。并调用serialize方法 ```java protected void serialize( DataTree dt, Map<Long, Integer> sessions, OutputArchive oa, FileHeader header) throws IOException { // this is really a programmatic error and not something that can // happen at runtime if (header == null) { throw new IllegalStateException("Snapshot's not open for writing: uninitialized header"); } header.serialize(oa, "fileheader"); SerializeUtils.serializeSnapshot(dt, oa, sessions); } ``` 在这里我们看到首先通过FileHeader对象序列化了文件头,包括magic、version、dbid内容,之后具体的内容交给SerializeUtils.serializeSnapshot方法 ```java public static void serializeSnapshot(DataTree dt, OutputArchive oa, Map<Long, Integer> sessions) throws IOException { HashMap<Long, Integer> sessSnap = new HashMap<Long, Integer>(sessions); oa.writeInt(sessSnap.size(), "count"); for (Entry<Long, Integer> entry : sessSnap.entrySet()) { oa.writeLong(entry.getKey().longValue(), "id"); oa.writeInt(entry.getValue().intValue(), "timeout"); } dt.serialize(oa, "tree"); } ``` 接下来是对所有的sessions进行序列化,首先保存了session的数量,并循环保存所有内容。而具体的内容又返回给了DataTree的序列化方法。 ```java public void serialize(OutputArchive oa, String tag) throws IOException { serializeAcls(oa); serializeNodes(oa); } ``` 这里我们看到依次序列化了acl和所有node 具体内容不再深入解析,就是依次调用Record接口的方法。 # 3. TxnLog 在TxnLog中方法比较多我们依次说明 ```java public interface TxnLog { /** * 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 * returns 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. * @return the last zxid of the logged transactions. * @throws IOException */ // 事务性操作的最新zxid long getLastLoggedZxid() throws IOException; /** * truncate the log to get in sync with the * leader. * @param zxid the zxid to truncate at. * @throws IOException */ // 清空日志,与Leader保持同步。该函数用于清空大于给定zxid的所有事务日志。 boolean truncate(long zxid) throws IOException; /** * the dbid for this transaction log. * @return the dbid for this transaction log. * @throws IOException */ // 获取数据库的id long getDbId() throws IOException; /** * commmit the trasaction and make sure * they are persisted * @throws IOException */ // 提交事务并进行确认,该函数主要用于提交事务日志至磁盘 void commit() throws IOException; /** * close the transactions logs */ // 关闭事务性日志 void close() throws IOException; /** * an iterating interface for reading * transaction logs. */ // 读取事务日志的迭代器接口 public interface TxnIterator { /** * 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; /** * close files and release the * resources * @throws IOException */ // 关闭文件释放资源 void close() throws IOException; } } ``` ## 3.1 核心接口 ### 3.1.1 append ```java @Override public synchronized boolean append(TxnHeader hdr, Record txn, TxnDigest digest) throws IOException { if (hdr == null) { return false; } //跟新zxid if (hdr.getZxid() <= lastZxidSeen) { LOG.warn( "Current zxid {} is <= {} for {}", hdr.getZxid(), lastZxidSeen, hdr.getType()); } else { lastZxidSeen = hdr.getZxid(); } //没有日志文件时创建 if (logStream == null) { 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()); //序列化日志,具体就是3个参数序列化后依次拼接 byte[] buf = Util.marshallTxnEntry(hdr, txn, digest); 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"); //写日志,并在结尾添加一个EOR字符,表示当前日志结束 Util.writeTxnBytes(oa, buf); return true; } ``` # 4 FileTxnSnapLog 这个类整合了快照与日志的方法。在代码中。我们直接使用的也是这个类 ## 4.1 初始化  我们看到这个类接收2个参数,快照和日志的路径 并对这些路径进行判断是否存在,不存在就创建,同时也创建了FileTxnLog和FileSnap对象
回帖
消灭零回复
提交回复
热议榜
java 相关知识分享
8
好的程序员与不好的程序员
6
写给工程师的十条精进原则
5
spring boot以jar包运行配置的logback日志文件没生成
5
一步一步分析SpringBoot启动源码(一)
5
MockMvc测试
5
【吐槽向】是不是有个吐槽的板块比较好玩
4
logstash jdbc同步mysql多表数据到elasticsearch
3
IntelliJ IDEA 优质License Server
3
.gitignore忽略规则
3
SpringBoot启动源码分析
3
一步一步分析SpringBoot启动源码(三)
3
2
一步一步分析SpringBoot启动源码(二)
2
积分不够将无法发表新帖
2
官方产品
Meta-Boot - 基于MCN
MCN - 快速构建SpringBoot应用
微信扫码关注公众号