package volume

import (
    "github.com/syndtr/goleveldb/leveldb"
    "sync"
    "encoding/binary"
    "github.com/syndtr/goleveldb/leveldb/util"
    "errors"
    "path/filepath"
    "strconv"
    "fmt"
)

const (
    ReversedsizeOffsetPrefix = '\x11' //key= "\x01"+Reversesize(8 byte)+offset(8 byte) value=[]
    OffsetSizePrefix = '\x22' //key= "\x02"+offset(8 byte)+size(8 byte) value=[]
)

/*
status主要存储空闲块的offset size
 */
type Status struct {
    path       string
    db         *leveldb.DB
    spaceMutex sync.Mutex
}
//创建空闲文件  元数据
func NewStatus(dir string, vid uint64) (status *Status, err error) {
    path := filepath.Join(dir, strconv.FormatUint(vid, 10) + ".status")
    status = new(Status)
    status.path = path
    status.db, err = leveldb.OpenFile(path, nil)
    return status, err
}
//分配空间
func (s *Status)newSpace(size uint64) (offset uint64, err error) {
    s.spaceMutex.Lock()
    defer s.spaceMutex.Unlock()

    //这里根据size倒序存储,使最大的空间最先被获取
    iter := s.db.NewIterator(util.BytesPrefix([]byte{ReversedsizeOffsetPrefix}), nil)
    defer iter.Release()
    iter.Next()
    key := iter.Key()
    if len(key) == 0 {
        return 0, errors.New("can't get free space")
    }

    freeSize := binary.BigEndian.Uint64(key[1:9]) ^ (^uint64(0))
    if freeSize < size {
        return 0, errors.New("can't get free space")
    }
    offset = binary.BigEndian.Uint64(key[9:])

    transaction, err := s.db.OpenTransaction()
    if err != nil {
        return 0, err
    }

    transaction.Delete(key, nil)

    key = getOffsetSizeKey(offset, freeSize)
    transaction.Delete(key, nil)

    //如果空闲块大小大于所请求大小,则将剩下空闲块,重新记录
    if freeSize > size {
        key = getReversedsizeOffset(offset + size, freeSize - size)
        transaction.Put(key, nil, nil)

        key = getOffsetSizeKey(offset + size, freeSize - size)
        transaction.Put(key, nil, nil)
    }

    err = transaction.Commit()
    return offset, err
}
//  释放文件空间
func (s *Status)freeSpace(offset uint64, size uint64) error {
    s.spaceMutex.Lock()
    defer s.spaceMutex.Unlock()
       //这里根据size倒序存储,使最大的空间最先被获取
    iter := s.db.NewIterator(util.BytesPrefix([]byte{OffsetSizePrefix}), nil)
    defer iter.Release()
    key := getOffsetSizeKey(offset, 0)
    iter.Seek(key)
    transaction, err := s.db.OpenTransaction()
    if err != nil {
        return err
    }
    //如果与下一块空闲块相邻,则合成一块空闲块
    key = iter.Key()
    if len(key) != 0 {
        nOffset := binary.BigEndian.Uint64(key[1:9])
        nSize := binary.BigEndian.Uint64(key[9:])
        if nOffset < offset + size {
            panic(fmt.Errorf("nOffset: %d < offset: %d + size: %d", nOffset, offset, size))
        } else if nOffset == offset + size {
            transaction.Delete(key, nil)
            size += nSize
            key = getReversedsizeOffset(nOffset, nSize)
            transaction.Delete(key, nil)
        }
    }
    //如果与上一块空闲块相邻,则合成一块空闲块
    iter.Prev()
    key = iter.Key()
    if len(key) != 0 {
        pOffset := binary.BigEndian.Uint64(key[1:9])
        pSize := binary.BigEndian.Uint64(key[9:])
        if pOffset + pSize > offset {
            panic(fmt.Errorf("pOffset: %d + pSize: %d > offset: %d", pOffset, pSize, offset))
        } else if pOffset + pSize == offset {
            transaction.Delete(key, nil)
            offset = pOffset
            size += pSize
            key = getReversedsizeOffset(pOffset, pSize)
            transaction.Delete(key, nil)
        }
    }
    key = getOffsetSizeKey(offset, size)
    transaction.Put(key, nil, nil)
    key = getReversedsizeOffset(offset, size)
    transaction.Put(key, nil, nil)
    return transaction.Commit()
}
//
func (s *Status)getMaxFreeSpace() uint64 {
    iter := s.db.NewIterator(util.BytesPrefix([]byte{ReversedsizeOffsetPrefix}), nil)
    defer iter.Release()
    iter.Next()
    key := iter.Key()
    if len(key) == 0 {
        return 0
    }
    freeSize := binary.BigEndian.Uint64(key[1:9]) ^ (^uint64(0))
    return freeSize
}
//获取偏移量 文件key
func getOffsetSizeKey(offset, size uint64) []byte {
    key := make([]byte, 1 + 16)
    key[0] = OffsetSizePrefix
    binary.BigEndian.PutUint64(key[1:9], offset)
    binary.BigEndian.PutUint64(key[9:], size)
    return key
}
//
func getReversedsizeOffset(offset, size uint64) []byte {
    key := make([]byte, 1 + 16)
    key[0] = ReversedsizeOffsetPrefix
    binary.BigEndian.PutUint64(key[9:], offset)
    binary.BigEndian.PutUint64(key[1:9], size ^ (^uint64(0)))
    return key
}

status.go的更多相关文章

  1. http status code

    属于转载 http status code:200:成功,服务器已成功处理了请求,通常这表示服务器提供了请求的网页 404:未找到,服务器未找到 201-206都表示服务器成功处理了请求的状态代码,说 ...

  2. ORACLE中STATUS为INACTIVE但是SERVER为SHARED状态的会话浅析

    我们知道当ORACLE数据库启用共享服务器模式时,通过共享服务器模式连接到数据库的会话是有一些特征的.在v$session里面,其SERVER的状态一般为SHARED和NONE, 为SHARED时,表 ...

  3. 重定向Http status code 303 和 302

    http 302 http 303 Http 302 302是一个普通的重定向代码.直观的看来是,请求者(浏览器或者模拟http请求)发起一个请求,然后服务端重定向到另一个地址.而事实上,服务端仅仅是 ...

  4. C#、JAVA操作Hadoop(HDFS、Map/Reduce)真实过程概述。组件、源码下载。无法解决:Response status code does not indicate success: 500。

    一.Hadoop环境配置概述 三台虚拟机,操作系统为:Ubuntu 16.04. Hadoop版本:2.7.2 NameNode:192.168.72.132 DataNode:192.168.72. ...

  5. 关于XHR对象中status范围的记录

    if(xhr.status >= 200 && xhr.status < 300 || xhr.status == 304){ // 成功执行区域 // 2XX表示有效响应 ...

  6. Job for httpd.service failed because the control process exited with error code. See "systemctl status httpd.service" and "journalctl -xe" for details

    thinkphp 在Apache上配置启用伪静态,重启Apache1 restart 竟然失败了,报错 Job for httpd.service failed because the control ...

  7. ajax response status list [转载]

    比较理想的解释方法应该以"状态:任务(目标)+过程+表现(或特征)"的表达模式来对这几个状态进行定义  [全文]  在<Pragmatic Ajax A Web 2.0 Pr ...

  8. Zabbix监控redis status

    概述 zabbix采用Trapper方式监控redis status 原理 redis-cli info命令得到redis服务器的统计信息,脚本对信息分两部分处理: (1)# Keyspace部分为Z ...

  9. Zabbix监控nginx-rtmp status(json版)

    与前面的文章 zabbix监控nginx-rtmp status(html版)区别只在于取值的页面不一样 http://127.0.0.1:81/control/get/all_streams sta ...

  10. 查看Mysql版本号 (最简单的是status )

    一.使用命令行模式进入mysql会看到最开始的提示符;二.命令行中使用status可以看到;三.使用系统函数等等,   查看版本信息 #1使用命令行模式进入mysql会看到最开始的提示符 Your M ...

随机推荐

  1. 用nodejs实现简单爬虫

    前言   本喵最近工作中需要使用node,并也想晋升为全栈工程师,所以开始了node学习之旅,在学习过程中, 我会总结一些实用的例子,做成博文和视频教程,以实例形式来理解体会node的用法,所以跟小猫 ...

  2. css区分ie8/ie9/ie10/ie11 chrome firefox的代码

    以下是几个主要浏览器的css  hack汇总: 现有css样式为: .class{ color:red; } 判断IE8以上的浏览器才执行的代码/* IE8+ */ .class{ color:red ...

  3. List集合中元素排序

    应用场景: 在开发中经常遇到要对List<Object>集合进行排序,并且是根据集合中的对象的某个属性来进行排序    --------以下就此做出的解决方案 public static ...

  4. Struts,Spring,Hibernate三大框架的

    1.Hibernate工作原理及为什么要用? 原理: 1.读取并解析配置文件 2.读取并解析映射信息,创建SessionFactory 3.打开Session 4.创建事务Transation 5.持 ...

  5. CSS 弹性容器

    该文章为英文原文译文及一些自己的拙见墙裂推荐读原文浏览原文请戳这里 : CSS-STRICKS 弹性布局 (Flexbox Layout) 什么是弹性布局 Flexbox Layout 模块旨在提供一 ...

  6. nvm使用笔记

    1.先发个中文博客的链接:http://www.cnblogs.com/kaiye/p/4937191.html 2.安装node版本的命令问题,版本号前面要加v,安装6.9.1的正确命令是: nvm ...

  7. Django error信息邮件通知功能配置部署

    1. 最近QA成为项目的重点,除了突破依赖外部表的阻力开始启用单元测试,还有一点就是对在线的生产服务的错误信息启用这个邮件通知功能,下面简单说一下启用方法: 1.发送邮件账号配置配置: EMAIL_H ...

  8. android点击返回键,如何做到不destory当前activity,只是stop。重新返回该activity的 时候可以直接使用,不需要创建新的activity实例

    问题描述,如题目: android点击返回键,顺序执行 pause,stop,destory. 以至于想重新进入这个activity的时候还要重新执行onCreate()方法,那么如何解决不再重新执行 ...

  9. html块级元素与行内元素

    1.关于行内元素和快元素的说明: 根据CSS规范的规定,每一个网页元素都有一个display属性,用于确定该元素的类型,每一个元素都有默认的display属性值,比如div元素,它的默认display ...

  10. tensorflow1.0.0 弃用了几个operator写法

    除法和取模运算符(/, //, %)现已匹配 Python(flooring)语义.这也适用于 tf.div 和 tf.mod.为了获取强制的基于整数截断的行为,你可以使用 tf.truncatedi ...