序列化

简介: 本文从源码角度分析Zookeeper的序列化机制,重点解析jute包中的InputArchive接口及其实现类BinaryInputArchive,介绍其在反序列化过程中的核心方法与数据读取逻辑,揭示Zookeeper在网络通信与数据存储中的序列化实现原理。

一、前言  在完成了前面的理论学习后,现在可以从源码角度来解析Zookeeper的细节,首先笔者想从序列化入手,因为在网络通信、数据存储中都用到了序列化,下面开始分析。二、序列化  序列化主要在zookeeper.jute包中,其中涉及的主要接口如下    · InputArchive    · OutputArchive    · Index    · Record2.1 InputArchive  其是所有反序列化器都需要实现的接口,其方法如下 InputArchive的类结构如下  1. BinaryInputArchive 2. CsvInputArchive 

Java

运行代码复制代码

public class BinaryInputArchive implements InputArchive {

   // DataInput接口,用于从二进制流中读取字节

   private DataInput in;

 

   // 静态方法,用于获取Archive

   static public BinaryInputArchive getArchive(InputStream strm) {

       return new BinaryInputArchive(new DataInputStream(strm));

   }

 

   // 内部类,对应BinaryInputArchive索引

   static private class BinaryIndex implements Index {

       private int nelems;

       BinaryIndex(int nelems) {

           this.nelems = nelems;

       }

       public boolean done() {

           return (nelems <= 0);

       }

       public void incr() {

           nelems--;

       }

   }

   /** Creates a new instance of BinaryInputArchive */

   // 构造函数

   public BinaryInputArchive(DataInput in) {

       this.in = in;

   }

 

   // 读取字节

   public byte readByte(String tag) throws IOException {

       return in.readByte();

   }

 

   // 读取boolean类型

   public boolean readBool(String tag) throws IOException {

       return in.readBoolean();

   }

 

   // 读取int类型

   public int readInt(String tag) throws IOException {

       return in.readInt();

   }

 

   // 读取long类型

   public long readLong(String tag) throws IOException {

       return in.readLong();

   }

 

   // 读取float类型

   public float readFloat(String tag) throws IOException {

       return in.readFloat();

   }

 

   // 读取double类型

   public double readDouble(String tag) throws IOException {

       return in.readDouble();

   }

 

   // 读取String类型

   public String readString(String tag) throws IOException {

       // 确定长度

       int len = in.readInt();

       if (len == -1) return null;

       byte b[] = new byte[len];

       // 从输入流中读取一些字节,并将它们存储在缓冲区数组b中

       in.readFully(b);

       return new String(b, "UTF8");

   }

 

   // 最大缓冲值

   static public final int maxBuffer = Integer.getInteger("jute.maxbuffer", 0xfffff);


   // 读取缓冲

   public byte[] readBuffer(String tag) throws IOException {

       // 确定长度

       int len = readInt(tag);

       if (len == -1) return null;

       // Since this is a rough sanity check, add some padding to maxBuffer to

       // make up for extra fields, etc. (otherwise e.g. clients may be able to

       // write buffers larger than we can read from disk!)

       if (len < 0 || len > maxBuffer + 1024) { // 检查长度是否合理

           throw new IOException("Unreasonable length = " + len);

       }

       byte[] arr = new byte[len];

       // 从输入流中读取一些字节,并将它们存储在缓冲区数组arr中

       in.readFully(arr);

       return arr;

   }

 

   // 读取记录

   public void readRecord(Record r, String tag) throws IOException {

       // 反序列化,动态调用

       r.deserialize(this, tag);

   }

 

   // 开始读取记录,实现为空

   public void startRecord(String tag) throws IOException {}

 

   // 结束读取记录,实现为空

   public void endRecord(String tag) throws IOException {}

 

   // 开始读取向量

   public Index startVector(String tag) throws IOException {

       // 确定长度

       int len = readInt(tag);

       if (len == -1) {

           return null;

       }

       // 返回索引

       return new BinaryIndex(len);

   }

 

   // 结束读取向量

   public void endVector(String tag) throws IOException {}

 

   // 开始读取Map

   public Index startMap(String tag) throws IOException {

       // 返回索引

       return new BinaryIndex(readInt(tag));

   }

 

   // 结束读取Map,实现为空

   public void endMap(String tag) throws IOException {}

 

}



// 读取并转化为字符

char c = (char) stream.read();

if (tag == null || "".equals(tag)) {

if (c != '\n' && c != '\r') { // 进行判断

throw new IOException("Error deserializing record.");

} else {

return;

}

}

if (c != '}') { // 进行判断

throw new IOException("Error deserializing "+tag);

}

// 读取并转化为字符

c = (char) stream.read();

if (c != ',') {

// 推回缓冲区

stream.unread(c);

}

return;

}

// 开始读取vector

public Index startVector(String tag) throws IOException {

char c1 = (char) stream.read();

char c2 = (char) stream.read();

if (c1 != 'v' || c2 != '{') {

throw new IOException("Error deserializing "+tag);

}

return new CsvIndex();

}

// 结束读取vector

public void endVector(String tag) throws IOException {

char c = (char) stream.read();

if (c != '}') {

throw new IOException("Error deserializing "+tag);

}

c = (char) stream.read();

if (c != ',') {

stream.unread(c);

}

return;

}

// 开始读取Map

public Index startMap(String tag) throws IOException {

char c1 = (char) stream.read();

char c2 = (char) stream.read();

if (c1 != 'm' || c2 != '{') {

throw new IOException("Error deserializing "+tag);

}

return new CsvIndex();

}

// 结束读取Map

public void endMap(String tag) throws IOException {

char c = (char) stream.read();

if (c != '}') {

throw new IOException("Error deserializing "+tag);

}

c = (char) stream.read();

if (c != ',') {

stream.unread(c);

}

return;

}

}

相关文章
|
7月前
|
监控 Java 测试技术
OOM排查之路:一次曲折的线上故障复盘
本文记录了一次Paimon数据湖与RocksDB集成服务线上频繁OOM的排查历程。通过分析线程暴增、堆外内存泄漏,最终定位到SDK中RocksDB的JNI内存未释放问题,并借助Flink重构写入链路彻底解决。分享了MAT、NMT、async-profiler等工具的实战经验与排查思路,为类似技术栈提供借鉴。
OOM排查之路:一次曲折的线上故障复盘
|
7月前
|
人工智能 JSON 数据挖掘
大模型应用开发中MCP与Function Call的关系与区别
MCP与Function Call是大模型应用中两大关键技术。前者为跨模型标准化通信协议,实现工具与模型解耦;后者是模型调用外部功能的内置机制。二者互补协作,推动AI应用向更开放、灵活、可扩展的方向发展。
|
7月前
|
Java 网络安全 开发工具
[MES]不合格订单接入提醒功能(☆☆☆) 1.代码运行
本文介绍入职后如何快速搭建开发环境并运行项目,包括克隆代码、配置JDK/Maven/Git等工具的求助策略,并模拟真实需求:实现不合格工单超30分钟自动通知(短信/钉钉),涉及Git、Maven、SpringBoot及定时任务技术,提升新人实战能力。
|
7月前
|
消息中间件 监控 Java
RocketMQ:底层Netty频繁OS OOM
本文记录了一例Java应用因Netty多ClassLoader加载导致堆外内存超限引发OS OOM的排查过程。通过NMT、Arthas等工具定位到多个PooledByteBufAllocator实例各自独立占用堆外内存,最终超出容器限制。建议业务调优JVM参数并推动中间件优化。
|
7月前
|
存储 缓存 NoSQL
Redis:内存陡增100%深度复盘
事故因大KEY调用量随流量增长,导致带宽占满,Redis内存使用率迅速达100%。虽有淘汰机制,但缓冲区激增(尤其Pub/Sub输出缓冲)占用大量内存,超出实例容量,致使SET/GET超时崩溃。根本原因为客户端缓冲区失控,非数据本身膨胀,最终Redis无法服务。
Redis:内存陡增100%深度复盘
|
7月前
|
存储 SQL 关系型数据库
第四章 数据库
本文详解MySQL核心知识点,涵盖char与varchar区别、事务ACID特性、索引结构(B+tree)、聚簇与二级索引、回表查询、索引创建原则及失效场景,并结合explain执行计划分析SQL性能优化策略,助力数据库高效设计与调优。
|
7月前
|
存储 缓存 运维
一场FullGC故障排查
本文记录了一次由Full GC引发的CPU使用率飙升至104%的问题排查过程。通过分析JVM堆内存,发现大对象(List&lt;Map&gt;)导致老年代频繁被占满,进而触发Full GC。使用JProfiler定位到问题根源:Excel数据以低效结构加载至内存且长期驻留,造成内存膨胀。最终提出“治本”与“治标”两类解决方案,并总结了线上高CPU问题的排查思路与经验。
一场FullGC故障排查
Day07
简介:本文涵盖分布式系统核心理论CAP与BASE,解析一致性、可用性与分区容错的权衡,介绍Seata AT模式的分布式事务执行流程,并探讨MQ消息防丢失、防重复消费及消息积压处理方案。
 Day07
|
7月前
|
测试技术
发布模式
蓝绿部署通过两套系统(运行的“绿色”与待发布的“蓝色”)实现零停机发布与快速回滚。金丝雀发布则逐步替换旧版本,适合大规模集群。A/B测试用于比较不同版本效果,三者各有适用场景,非万能方案。
|
7月前
|
存储 缓存 监控
EFC&CTO:缓存引发数据不一致问题排查与深度解析
EFC客户端更新缓存架构后,CTO测试出现data mismatch。排查发现因版本号回退,旧dv读取缓存中填充的NULL数据,导致pagecache被污染,脏页回刷时破坏文件系统数据。修复后验证通过。

热门文章

最新文章