zoukankan      html  css  js  c++  java
  • 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
        }
    }

  • 相关阅读:
    单例模式
    Curator Zookeeper分布式锁
    LruCache算法原理及实现
    lombok 简化java代码注解
    Oracle客户端工具出现“Cannot access NLS data files or invalid environment specified”错误的解决办法
    解决mysql Table ‘xxx’ is marked as crashed and should be repaired的问题。
    Redis 3.0 Cluster集群配置
    分布式锁的三种实现方式
    maven发布项目到私服-snapshot快照库和release发布库的区别和作用及maven常用命令
    How to Use Convolutional Neural Networks for Time Series Classification
  • 原文地址:https://www.cnblogs.com/zhangboyu/p/7461621.html
Copyright © 2011-2022 走看看