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
        }
    }

  • 相关阅读:
    微信小程序页面标签中无法使用的js语法
    React-Native真机调试
    微信小程序button设置宽度无效
    CSS禁止选中文本
    vue之 ref 和$refs的使用
    scrapy之 Spider Middleware(爬虫中间件)
    kafka
    Linux select、poll和epoll
    C/C++ 在一个一维数组中查找两个数,使得它们之和等于给定的某个值
    C/C++ 求浮点数平方根
  • 原文地址:https://www.cnblogs.com/zhangboyu/p/7461621.html
Copyright © 2011-2022 走看看