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. JSON 在Ajax数据交换中的简单运用

    随着浏览器内核更新,原先的json.js在最新的谷歌浏览下不管用了,运行报错,特此修改下代码,不使用json.js,使用Object自带的json转换方法,修改时间,2016年10月26日. 首先需要 ...

  2. 一个div在另一个div中水平垂直的方法

    html <div id="main"> <div id="box"> 一个div在另一个div中垂直居中实现方法 </div&g ...

  3. 【作业2.0】HansBug的5-7次OO作业分析与小结,以及一些个人体会

    不知不觉又做了三次作业,容我在本文胡言乱语几句2333. 第五次作业 第五次作业是前面的电梯作业的多线程版本,难度也有了一些提升.(点击就送指导书) 类图 程序的类图结构如下: UML时序图 程序的逻 ...

  4. PuTTY的下载安装和基本使用方法教程

    PuTTY是一款开源(Open Source Software)的连接软件,主要由Simon Tatham维护,使用MIT许可证授权.包含的组件有:PuTTY, PuTTYgen,PSFTP, PuT ...

  5. iOS 博客资源精选

    摘要:记录一些网上非常牛的人写的博文.收藏起来. 以备日后需要时学习备用. 1:iOS中UIWebView的Javascript与Objective-C通信 http://imchao.net/201 ...

  6. What’s new in Channels 2 摘译

    最近准备在一个老Django项目上启用Channels,Channels于今年2月2日发布2.0版本,这个版本包含很多不向前兼容的特性,为了新特性调研的需要,也为了方便社区,我新版本的What's N ...

  7. hadoop 2.x安装:完全分布式安装

    1. 安装环境 本文使用三台CentOS6.4虚拟机模拟完全分布式环境.前五个过程和hadoop1.x安装相同 1.1. 安装环境 项目 参数 主操作系统 Windows 10 64 bit,8GB内 ...

  8. 【数据可视化之Flask】快速设计和部署Flask网站

    Flask是Python应用于WEB开发的第三方开源框架,以设计简单高效著称.我也尝试过Django,相对于Flask显得更加全面同样也更加笨重,并且我也不需要它的后台管理功能,因此选择了Flask作 ...

  9. JavaScript对json操作小记

    JSON是一种轻量级的数据交换格式,同时,JSON是 JavaScript 原生格式,因此我们可以直接处理它不需要依赖任何工具包或者插件.因此,好多后台都会选择返回给前端这种非常友好的数据格式. 引子 ...

  10. htmlparser 学习

    htmlparser 学习系列 htmlparser 使用法使用与详解