volume.go
package volume
import (
"os"
"path/filepath"
"strconv"
"sync"
"time"
"encoding/binary"
"errors"
)
var (
TruncateSize uint64 = 1 << 30 //1GB
MaxVolumeSize uint64 = 512 * TruncateSize //512GB
)
type Volume struct {
Id uint64
WriteAble bool
index Index
status *Status
dataFile *os.File
mutex sync.Mutex
}
//创建一个卷 或者磁盘空间
func NewVolume(dir string, vid uint64) (v *Volume, err error) {
path := filepath.Join(dir, strconv.FormatUint(vid, 10) + ".data")
v = new(Volume)
v.Id = vid
v.dataFile, err = os.OpenFile(path, os.O_CREATE | os.O_RDWR, 0666)
if err != nil {
if os.IsPermission(err) {//判断是不是权限错误
v.dataFile, err = os.OpenFile(path, os.O_RDONLY, 0)
if err != nil {
return nil, err
}
v.WriteAble = false
} else {
return nil, err
}
}
v.WriteAble = true
v.index, err = NewLevelDBIndex(dir, vid)
if err != nil {
return nil, err
}
v.status, err = NewStatus(dir, vid)
if err != nil {
return nil, err
}
return v, nil
}
//实现index接口
//
func (v *Volume)Get(fid uint64) (*File, error) {
fi, err := v.index.Get(fid)
if err == nil {
return &File{DataFile: v.dataFile, Info: fi}, nil
} else {
return nil, err
}
}
//删除文件
func (v *Volume)Delete(fid uint64, fileName string) error {
v.mutex.Lock()
defer v.mutex.Unlock()
file, err := v.Get(fid)
if err != nil {
return err
} else if file.Info.FileName != fileName {
return errors.New("filename is wrong")
}
//因为文件内容前后都写入fid(8 byte) 要一起释放
err = v.status.freeSpace(file.Info.Offset - 8, file.Info.Size + 16)
if err != nil {
return err
}
err = v.index.Delete(fid)
return err
}
//创建文件
func (v *Volume)NewFile(fid uint64, fileName string, size uint64) (f *File, err error) {
v.mutex.Lock()
defer v.mutex.Unlock()
if v.index.Has(fid) {
return nil, errors.New("fid is existed")
}
offset, err := v.newSpace(size + 16)
if err != nil {
return nil, err
}
defer func() {
if err != nil {
if e := v.status.freeSpace(offset, size + 16); e != nil {
panic(e)
}
}
}()
//在文件内容前后都写入fid
b := make([]byte, 8)
binary.BigEndian.PutUint64(b, fid)
_, err = v.dataFile.WriteAt(b, int64(offset))
if err != nil {
return nil, err
}
_, err = v.dataFile.WriteAt(b, int64(offset + 8 + size))
if err != nil {
return nil, err
}
fileInfo := &FileInfo{
Fid: fid,
Offset: offset + 8,
Size: size,
Ctime: time.Now(),
Mtime: time.Now(),
Atime: time.Now(),
FileName: fileName,
}
err = v.index.Set(fileInfo)
if err != nil {
return nil, err
} else {
return &File{DataFile: v.dataFile, Info: fileInfo}, nil
}
}
//清空文件空间
func (v *Volume)truncate() {
currentDatafileSize := v.GetDatafileSize()
if currentDatafileSize >= MaxVolumeSize {
return
}
//清空指定偏移量位置的数据
err := v.dataFile.Truncate(int64(currentDatafileSize) + int64(TruncateSize))
if err != nil {
panic(err)
}
//释放文件空间
err = v.status.freeSpace(currentDatafileSize, TruncateSize)
if err != nil {
panic(err)
}
}
//分配新的文件空间
func (v *Volume)newSpace(size uint64) (uint64, error) {
offset, err := v.status.newSpace(size)
if err == nil {
return offset, err
}
v.truncate()
return v.status.newSpace(size)
}
//资源释放
func (v *Volume)Close() {
v.mutex.Lock()
//v.status.spaceMutex.Lock()
//因为要退出,所以不解锁,禁止读写
//defer v.rwMutex.Unlock()
//将所有资源释放
v.dataFile.Close()
v.dataFile = nil
v.status.db.Close()
v.status = nil
v.index.Close()
v.index = nil
}
//获取数据文件大小
func (v *Volume)GetDatafileSize() uint64 {
fi, err := v.dataFile.Stat()
if err != nil {
panic(err)
}
return uint64(fi.Size())
}
//获取最大释放文件空间
func (v *Volume)GetMaxFreeSpace() uint64 {
currentDatafileSize := v.GetDatafileSize()
//以块方式存储,所以自由空间无法直接相加
maxFreeSpace := v.status.getMaxFreeSpace()
if currentDatafileSize < MaxVolumeSize {
freeSpace := MaxVolumeSize - currentDatafileSize
if freeSpace > maxFreeSpace {
maxFreeSpace = freeSpace
}
}
//fid前后各占8个字节
if maxFreeSpace > 16 {
return maxFreeSpace - 16
} else {
return 0
}
}
volume.go的更多相关文章
- Java中实现SAX解析xml文件到MySQL数据库
大致步骤: 1.Java bean 2.DBHelper.java 3.重写DefaultHandler中的方法:MyHander.java 4.循环写数据库:SAXParserDemo.java ① ...
- CSharpGL(8)使用3D纹理渲染体数据 (Volume Rendering) 初探
CSharpGL(8)使用3D纹理渲染体数据 (Volume Rendering) 初探 2016-08-13 由于CSharpGL一直在更新,现在这个教程已经不适用最新的代码了.CSharpGL源码 ...
- 理解Docker(8):Docker 存储之卷(Volume)
(1)Docker 安装及基本用法 (2)Docker 镜像 (3)Docker 容器的隔离性 - 使用 Linux namespace 隔离容器的运行环境 (4)Docker 容器的隔离性 - 使用 ...
- Docker Volume 之权限管理(转)
Volume数据卷是Docker的一个重要概念.数据卷是可供一个或多个容器使用的特殊目录,可以为容器应用存储提供有价值的特性: 持久化数据与容器的生命周期解耦:在容器删除之后数据卷中的内容可以保持.D ...
- NFS Volume Provider(Part III) - 每天5分钟玩转 OpenStack(64)
今天我们将前一小节创建的 NFS volume “nfs-vol-1” attach 到 instance “c2”上. 这里我们重点关注 nova-compute 如何将“nfs-vol-1” at ...
- NFS Volume Provider(Part II) - 每天5分钟玩转 OpenStack(63)
上一节我们将 NFS volume provider 配置就绪,本节将创建 volume. 创建 volume 创建 NFS volume 操作方法与 LVM volume 一样,唯一区别是在 vol ...
- NFS Volume Provider(Part I) - 每天5分钟玩转 OpenStack(62)
cinder-volume 支持多种 volume provider,前面我们一直使用的是默认的 LVM,本节我们将增加 NFS volume provider. 虽然 NFS 更多地应用在实验或小规 ...
- Boot from Volume - 每天5分钟玩转 OpenStack(61)
Volume 除了可以用作 instance 的数据盘,也可以作为启动盘(Bootable Volume),那么如何使 volume 成为 bootable 呢? 现在我们打开 instance 的 ...
- Restore Volume 操作 - 每天5分钟玩转 OpenStack(60)
前面我们 backup 了 voluem,今天我们将讨论如何 restore volume. restore 的过程其实很简单,两步走: 在存储节点上创建一个空白 volume. 将 backup 的 ...
- Backup Volume 操作 - 每天5分钟玩转 OpenStack(59)
本节我们讨论 volume 的 Backup 操作. Backup 是将 volume 备份到别的地方(备份设备),将来可以通过 restore 操作恢复. Backup VS Snapshot 初看 ...
随机推荐
- Runtime - ③ - 分类Category探究
写博客只是为了让自己学的更深刻,参考:https://tech.meituan.com/DiveIntoCategory.html 分类(Category)是个啥玩意儿这里就不多介绍了,这里主要是研究 ...
- pandas数据处理基础——筛选指定行或者指定列的数据
pandas主要的两个数据结构是:series(相当于一行或一列数据机构)和DataFrame(相当于多行多列的一个表格数据机构). 本文为了方便理解会与excel或者sql操作行或列来进行联想类比 ...
- Javascript、CSS、HTML面试题
1 JS中的三种弹出式消息提醒(警告窗口.确认窗口.信息输入窗口)的命令是什么? alert confirm prompt 2声明一个已经存在一个CSS有几种方式? 1.导入一个已经存 ...
- plsql developer 使用 oracle instantclient的安装和配置
本文由ibyedo1贡献 1.下载 oracle instantclient basic package,在 oracle 官网下载就可以,地址如下: http://www.oracle.com/te ...
- SQL Server 远程更新目标表数据
分享一个远程更新目标库数据的存储过程,适用于更新列名一致,主键为Int类型,可远程链接的数据库. ** 温馨提示:如需转载本文,请注明内容出处.** 本文连接:http://www.cnblogs.c ...
- Visual Studio Community 2013,功能完整,免费使用
http://www.infoq.com/cn/news/2014/11/VSC2013 微软刚刚宣布了.NET平台的开源计划,与此同时,它还推出了源自Visual Studio Profession ...
- pg_dump命令帮助信息
仅为参考查阅方便,完全命令行帮助信息,无阅读价值. pg_dump dumps a database as a text file or to other formats. Usage: pg_du ...
- 与班尼特·胡迪一起做生意 (HZUN-2261)
与班尼特·胡迪一起做生意 AC Time Limit: 1 s Memory Limit: 256 MB Description 马爷作为2-80X的资深土财主,靠着敏锐的商业嗅觉不断 ...
- Linux的动态库与静态库
1.动态库与静态库简介 在实际的软件开发中,为了方便使用一些被重复调用的公共代码,我们经常将这些公共的函数编译成动态库或静态库.我们知道程序一般要经过预处理.编译.汇编和链接这几个步骤才能变成可执行的 ...
- java集合的contains(obj)方法的实现
在实际项目中我们通常会有一个需求就是:想知道在一个列表中是否包含某一个对象 这里ArrayList表.HashSet表和HashMap表都提供了一个contains(obj)方法, 下面说一下两个列表 ...