官方的解释这个类为:

  1. /**
  2. * A simple, durable, atomic K/V database. *Very inefficient*, should only be
  3. * used for occasional reads/writes. Every read/write hits disk.
  4. */

简单来理解就是这个类每次读写都会将一个Map<Object, Object>的对象序列化存储到磁盘中,读的时候将其反序列化。

构造函数指定的参数就是你在磁盘中存储的目录,同时也作为VersionedStore的构造函数的参数。

这些文件在目录中是以一个long类型的id进行命名

  1. public LocalState(String backingDir) throws IOException {
  2. _vs = new VersionedStore(backingDir);
  3. }

snapshot函数,找到最近的版本,将其反序列化

  1. public synchronized Map<Object, Object> snapshot() throws IOException {
  2. int attempts = 0;
  3. while (true) {
  4. String latestPath = _vs.mostRecentVersionPath(); //获取最近的版本
  5. if (latestPath == null)
  6. return new HashMap<Object, Object>();
  7. try {
  8. return (Map<Object, Object>) Utils.deserialize(FileUtils
  9. .readFileToByteArray(new File(latestPath)));
  10. } catch (IOException e) {
  11. attempts++;
  12. if (attempts >= 10) {
  13. throw e;
  14. }
  15. }
  16. }
  17. }
  1. public Object get(Object key) throws IOException {
  2. return snapshot().get(key);
  3. }
  4.  
  5. public synchronized void put(Object key, Object val) throws IOException {
  6. put(key, val, true);
  7. }
  8.  
  9. public synchronized void put(Object key, Object val, boolean cleanup)
  10. throws IOException {
  11. Map<Object, Object> curr = snapshot();
  12. curr.put(key, val);
  13. persist(curr, cleanup); //persist会将其写入到磁盘中
  14. }
  15.  
  16. public synchronized void remove(Object key) throws IOException {
  17. remove(key, true);
  18. }
  19.  
  20. public synchronized void remove(Object key, boolean cleanup)
  21. throws IOException {
  22. Map<Object, Object> curr = snapshot();
  23. curr.remove(key);
  24. persist(curr, cleanup);
  25. }
  26.  
  27. public synchronized void cleanup(int keepVersions) throws IOException {
  28. _vs.cleanup(keepVersions);
  29. }

可以看到,基本暴露的接口都通过synchronized关键字来保证串行化的操作,同时多次调用了以下的persist方法,

  1. private void persist(Map<Object, Object> val, boolean cleanup)
  2. throws IOException {
  3. byte[] toWrite = Utils.serialize(val);
  4. String newPath = _vs.createVersion(); //创建一个新的版本号
  5. FileUtils.writeByteArrayToFile(new File(newPath), toWrite);
  6. _vs.succeedVersion(newPath); //如果写入成功,那么会生成 id.version 文件来声明该文件写入成功
  7. if (cleanup)
  8. _vs.cleanup(4); //默认保留4个版本
  9. }

接下来看看VersionedStore这个类,它是进行实际存储操作的类,提供了接口给LocalState

  1. public void succeedVersion(String path) throws IOException {
  2. long version = validateAndGetVersion(path); //验证一下这个文件是否存在
  3. // should rewrite this to do a file move
  4. createNewFile(tokenPath(version)); //创建对应的 id.version 文件说明写入成功
  5. }

path的值是一个long类型的id,表示对应的文件

  1. private long validateAndGetVersion(String path) {
  2. Long v = parseVersion(path);
  3. if (v == null)
  4. throw new RuntimeException(path + " is not a valid version");
  5. return v;
  6. }

//解析出版本号,如果以.version结尾的,去掉.version

  1. private Long parseVersion(String path) {
  2. String name = new File(path).getName();
  3. if (name.endsWith(FINISHED_VERSION_SUFFIX)) {
  4. name = name.substring(0,
  5. name.length() - FINISHED_VERSION_SUFFIX.length());
  6. }
  7. try {
  8. return Long.parseLong(name);
  9. } catch (NumberFormatException e) {
  10. return null;
  11. }
  12. }
  1. createNewFile(tokenPath(version)); //创建对应的 id.version 文件说明写入成功

token file就是一种标志文件,用于标志对应的文件已经写入成功,以.version 结尾

  1. private String tokenPath(long version) {
  2. return new File(_root, "" + version + FINISHED_VERSION_SUFFIX)
  3. .getAbsolutePath();
  4. }
  1. private void createNewFile(String path) throws IOException {
  2. new File(path).createNewFile();
  3. }

cleanup函数,保留versionsToKeep版本,清除其他的版本

  1. public void cleanup(int versionsToKeep) throws IOException {
  2. List<Long> versions = getAllVersions(); //获取所有的版本,这个返回的是以倒序排列的,最新的版本在最前面
  3. if (versionsToKeep >= 0) {
  4. versions = versions.subList(0,
  5. Math.min(versions.size(), versionsToKeep)); //所以可以用subList来得到需要的版本
  6. }
  7. HashSet<Long> keepers = new HashSet<Long>(versions); //存在HashSet中方便快速存取
  8.  
  9. for (String p : listDir(_root)) {
  10. Long v = parseVersion(p);
  11. if (v != null && !keepers.contains(v)) {
  12. deleteVersion(v); //删除其他的版本
  13. }
  14. }
  15. }

getAllVersions,注意这里是获取所有以version结尾的文件,也就是说所有写入成功的文件,不包括某些还没写成功的文件

  1. /**
  2. * Sorted from most recent to oldest
  3. */
  4. public List<Long> getAllVersions() throws IOException {
  5. List<Long> ret = new ArrayList<Long>();
  6. for (String s : listDir(_root)) { //获取该目录下的所有文件
  7. if (s.endsWith(FINISHED_VERSION_SUFFIX)) {
  8. ret.add(validateAndGetVersion(s)); //验证该文件是否存在
  9. }
  10. }
  11. Collections.sort(ret);
  12. Collections.reverse(ret); //逆序排列
  13. return ret;
  14. }

删除对应的version文件和token文件

  1. public void deleteVersion(long version) throws IOException {
  2. File versionFile = new File(versionPath(version));
  3. File tokenFile = new File(tokenPath(version));
  4.  
  5. if (versionFile.exists()) {
  6. FileUtils.forceDelete(versionFile);
  7. }
  8. if (tokenFile.exists()) {
  9. FileUtils.forceDelete(tokenFile);
  10. }
  11. }

在最开始的地方,snapshot()函数调用了 mostRecentVersionPath() 来获取最近的版本,也就是调用getAllVersions,然后拿到最新的version

  1. public String mostRecentVersionPath() throws IOException {
  2. Long v = mostRecentVersion();
  3. if (v == null)
  4. return null;
  5. return versionPath(v);
  6. }
  1. public Long mostRecentVersion() throws IOException {
  2. List<Long> all = getAllVersions();
  3. if (all.size() == 0)
  4. return null;
  5. return all.get(0);
  6. }

如果提供了version号的话,可以看到是取出了比这个version号小的最大的version

  1. public String mostRecentVersionPath(long maxVersion) throws IOException {
  2. Long v = mostRecentVersion(maxVersion);
  3. if (v == null)
  4. return null;
  5. return versionPath(v);
  6. }
  1. public Long mostRecentVersion(long maxVersion) throws IOException {
  2. List<Long> all = getAllVersions();
  3. for (Long v : all) {
  4. if (v <= maxVersion) //取出比maxVersion小的最大version
  5. return v;
  6. }
  7. return null;
  8. }

Storm中的LocalState 代码解析的更多相关文章

  1. linux内存管理--slab及其代码解析

    Linux内核使用了源自于 Solaris 的一种方法,但是这种方法在嵌入式系统中已经使用了很长时间了,它是将内存作为对象按照大小进行分配,被称为slab高速缓存. 内存管理的目标是提供一种方法,为实 ...

  2. Postgres中postmaster代码解析(中)

    今天我们对postmaster的以下细节进行讨论: backend的启动和client的连接请求的认证 客户端取消查询时的处理 接受pg_ctl的shutdown请求进行shutdown处理 2.与前 ...

  3. Python中sort和sorted函数代码解析

    Python中sort和sorted函数代码解析 本文研究的主要是Python中sort和sorted函数的相关内容,具体如下. 一.sort函数 sort函数是序列的内部函数 函数原型: L.sor ...

  4. 捕捉WPF应用程序中XAML代码解析异常

    原文:捕捉WPF应用程序中XAML代码解析异常 由于WPF应用程序中XAML代码在很多时候是运行时加载处理的.比如DynamicResource,但是在编译或者运行的过程中,编写的XAML代码很可能有 ...

  5. .NET Core中的认证管理解析

    .NET Core中的认证管理解析 0x00 问题来源 在新建.NET Core的Web项目时选择“使用个人用户账户”就可以创建一个带有用户和权限管理的项目,已经准备好了用户注册.登录等很多页面,也可 ...

  6. VBA常用代码解析

    031 删除工作表中的空行 如果需要删除工作表中所有的空行,可以使用下面的代码. Sub DelBlankRow() DimrRow As Long DimLRow As Long Dimi As L ...

  7. Storm中遇到的日志多次重写问题(一)

    业务描述: 统计从kafka spout中读取的数据条数,以及写入redis的数据的条数,写入hdfs的数据条数,写入kafaka的数据条数.并且每过5秒将数据按照json文件的形式写入日志.其中保存 ...

  8. OS中atomic的实现解析

    OS中atomic的实现解析 转自:http://my.oschina.net/majiage/blog/267409    摘要 atomic属性线程安全,会增加一定开销,但有些时候必须自定义ato ...

  9. [nRF51822] 10、基础实验代码解析大全 · 实验15 - RTC

    一.实验内容: 配置NRF51822 的RTC0 的TICK 频率为8Hz,COMPARE0 匹配事件触发周期为3 秒,并使能了TICK 和COMPARE0 中断. TICK 中断中驱动指示灯D1 翻 ...

随机推荐

  1. bzoj 1324 Exca王者之剑(黑白染色,最小割)

    [题意] 两相邻点不能同时选,选一个点集使得权值和最大. 出题人语文好... [思路] 将图进行黑白二染色,然后构建最小割模型. [代码] #include<set> #include&l ...

  2. C++设计模式——建造者模式

    建造者模式 在GOF的<设计模式 可复用面向对象软件的基础>中是这样说的:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示. 这句话,似懂非懂的.一个复杂对象的创建 ...

  3. Install_pygments

    安装Pygments语法高亮 On OS X Leopard, Snow Leopard 1 $ sudo easy_install Pygments Alternatively on OS X wi ...

  4. Codevs No.1245 最小的N个和

    2016-05-31 18:52:15 题目链接: 最小的N个和 Codevs No.1245 题目大意: 给两个等长数列,各取一个数求和,找到最小的N组 解法: 堆优化的大暴力 直接枚举所有可能在最 ...

  5. HDU 2045 不容易系列之(3)—— LELE的RPG难题 (递推)

    题意:略. 析:首先是假设前n-2个已经放好了,那么放第 n 个时,先考虑一下第 n-1 放的是什么,那么有两种情况. 如果n-1放的是和第1个一样的,那么第 n 个就可以在n-2的基础上放2个,也就 ...

  6. 三星手机 Samsung Galaxy S3 无法复制粘贴的不完美解决方法

    问题简单描述 从上周开始我的Samsung Galaxy S3手机就无法实现复制粘贴功能了,每次复制时都提示复制到了剪贴板,但是粘贴时就会发现根本粘贴不了,无法打开剪贴板.真的是莫明其妙啊,我的手机没 ...

  7. hibernate一对多关系配置

    一.     表信息 公司表 cId cName cAdress Null Null Null 表t_company 员工表 sId sName sAge cId Null Null Null Nul ...

  8. .Net 代码安全保护产品DNGuard HVM使用

    前辈人物写的程序啊! 官方网站:http://www.dnguard.net/index.aspx 官方博客:http://www.cnblogs.com/rick/ (很久没更新了) 原文http: ...

  9. CSS基础(01)

    1. Css基础 1.1 CSS(层叠样式表 Multiple Styles)   CSS 是 Cascading Style Sheets(层叠样式表)的简称. CSS 语言是一种标记语言,它不需要 ...

  10. Node.js Crypto 加密算法库

    Crypto库是随Nodejs内核一起打包发布的,主要提供了加密.解密.签名.验证等功能.Crypto利用OpenSSL库来实现它的加密技术,它提供OpenSSL中的一系列哈希方法,包括hmac.ci ...