Files
EdgeNode/internal/utils/bfs/meta_file.go

381 lines
7.4 KiB
Go
Raw Normal View History

// Copyright 2024 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
package bfs
import (
"bytes"
"encoding/binary"
"github.com/TeaOSLab/EdgeNode/internal/utils/fasttime"
2024-05-11 09:23:54 +08:00
"github.com/TeaOSLab/EdgeNode/internal/utils/zero"
"io"
"os"
"sync"
)
const MFileExt = ".m"
const Version1 = 1
type MetaFile struct {
fp *os.File
filename string
2024-04-27 20:11:50 +08:00
headerMap map[string]*LazyFileHeader // hash => *LazyFileHeader
mu *sync.RWMutex // TODO 考虑单独一个不要和bFile共享
isModified bool
2024-04-27 20:11:50 +08:00
modifiedHashMap map[string]zero.Zero // hash => Zero
}
2024-04-26 18:44:29 +08:00
func OpenMetaFile(filename string, mu *sync.RWMutex) (*MetaFile, error) {
fp, err := os.OpenFile(filename, os.O_CREATE|os.O_RDWR, 0666)
if err != nil {
return nil, err
}
var mFile = &MetaFile{
filename: filename,
fp: fp,
2024-04-27 20:11:50 +08:00
headerMap: map[string]*LazyFileHeader{},
mu: mu,
modifiedHashMap: map[string]zero.Zero{},
}
// 从文件中加载已有的文件头信息
err = mFile.load()
if err != nil {
return nil, err
}
return mFile, nil
}
func (this *MetaFile) load() error {
2024-04-27 07:09:14 +08:00
AckReadThread()
_, err := this.fp.Seek(0, io.SeekStart)
2024-04-27 07:09:14 +08:00
ReleaseReadThread()
if err != nil {
return err
}
2024-04-27 20:11:50 +08:00
// TODO 检查文件是否完整
var buf = make([]byte, 4<<10)
var blockBytes []byte
for {
2024-04-27 07:09:14 +08:00
AckReadThread()
n, readErr := this.fp.Read(buf)
2024-04-27 07:09:14 +08:00
ReleaseReadThread()
if n > 0 {
blockBytes = append(blockBytes, buf[:n]...)
for len(blockBytes) > 4 {
var l = int(binary.BigEndian.Uint32(blockBytes[:4])) + 4 /* Len **/
if len(blockBytes) < l {
break
}
action, hash, data, decodeErr := DecodeMetaBlock(blockBytes[:l])
if decodeErr != nil {
return decodeErr
}
switch action {
case MetaActionNew:
2024-04-27 20:11:50 +08:00
this.headerMap[hash] = NewLazyFileHeaderFromData(data)
case MetaActionRemove:
delete(this.headerMap, hash)
}
blockBytes = blockBytes[l:]
}
}
if readErr != nil {
if readErr == io.EOF {
break
}
return readErr
}
}
return nil
}
func (this *MetaFile) WriteMeta(hash string, status int, expiresAt int64, expectedFileSize int64) error {
2024-04-27 20:11:50 +08:00
this.mu.Lock()
defer this.mu.Unlock()
2024-04-27 20:11:50 +08:00
this.headerMap[hash] = NewLazyFileHeader(&FileHeader{
Version: Version1,
ExpiresAt: expiresAt,
Status: status,
ExpiredBodySize: expectedFileSize,
IsWriting: true,
2024-04-27 20:11:50 +08:00
})
this.modifiedHashMap[hash] = zero.Zero{}
return nil
}
func (this *MetaFile) WriteHeaderBlockUnsafe(hash string, bOffsetFrom int64, bOffsetTo int64) error {
2024-04-27 20:11:50 +08:00
lazyHeader, ok := this.headerMap[hash]
if !ok {
return nil
}
2024-04-27 20:11:50 +08:00
header, err := lazyHeader.FileHeaderUnsafe()
if err != nil {
return err
}
// TODO 合并相邻block
header.HeaderBlocks = append(header.HeaderBlocks, BlockInfo{
BFileOffsetFrom: bOffsetFrom,
BFileOffsetTo: bOffsetTo,
})
this.modifiedHashMap[hash] = zero.Zero{}
return nil
}
func (this *MetaFile) WriteBodyBlockUnsafe(hash string, bOffsetFrom int64, bOffsetTo int64, originOffsetFrom int64, originOffsetTo int64) error {
2024-04-27 20:11:50 +08:00
lazyHeader, ok := this.headerMap[hash]
if !ok {
return nil
}
2024-04-27 20:11:50 +08:00
header, err := lazyHeader.FileHeaderUnsafe()
if err != nil {
return err
}
// TODO 合并相邻block
header.BodyBlocks = append(header.BodyBlocks, BlockInfo{
OriginOffsetFrom: originOffsetFrom,
OriginOffsetTo: originOffsetTo,
BFileOffsetFrom: bOffsetFrom,
BFileOffsetTo: bOffsetTo,
})
this.modifiedHashMap[hash] = zero.Zero{}
return nil
}
func (this *MetaFile) WriteClose(hash string, headerSize int64, bodySize int64) error {
// TODO 考虑单个hash多次重复调用的情况
this.mu.Lock()
2024-04-27 20:11:50 +08:00
lazyHeader, ok := this.headerMap[hash]
if !ok {
2024-04-27 20:11:50 +08:00
this.mu.Unlock()
return nil
}
2024-04-27 20:11:50 +08:00
header, err := lazyHeader.FileHeaderUnsafe()
if err != nil {
return err
}
this.mu.Unlock()
// TODO 检查bodySize和expectedBodySize是否一致如果不一致则从headerMap中删除
header.ModifiedAt = fasttime.Now().Unix()
header.HeaderSize = headerSize
header.BodySize = bodySize
header.Compact()
blockBytes, err := header.Encode(hash)
if err != nil {
return err
}
this.mu.Lock()
defer this.mu.Unlock()
2024-04-27 07:09:14 +08:00
AckReadThread()
_, err = this.fp.Seek(0, io.SeekEnd)
2024-04-27 07:09:14 +08:00
ReleaseReadThread()
if err != nil {
return err
}
2024-04-27 07:09:14 +08:00
AckWriteThread()
_, err = this.fp.Write(blockBytes)
2024-04-27 07:09:14 +08:00
ReleaseWriteThread()
this.isModified = true
return err
}
func (this *MetaFile) RemoveFile(hash string) error {
this.mu.Lock()
defer this.mu.Unlock()
_, ok := this.headerMap[hash]
if ok {
delete(this.headerMap, hash)
}
if ok {
blockBytes, err := EncodeMetaBlock(MetaActionRemove, hash, nil)
if err != nil {
return err
}
2024-04-27 07:09:14 +08:00
AckWriteThread()
_, err = this.fp.Write(blockBytes)
2024-04-27 07:09:14 +08:00
ReleaseWriteThread()
if err != nil {
return err
}
this.isModified = true
}
return nil
}
2024-04-26 18:44:29 +08:00
func (this *MetaFile) FileHeader(hash string) (header *FileHeader, ok bool) {
this.mu.RLock()
defer this.mu.RUnlock()
2024-04-27 20:11:50 +08:00
lazyHeader, ok := this.headerMap[hash]
if ok {
var err error
header, err = lazyHeader.FileHeaderUnsafe()
if err != nil {
ok = false
}
}
return
}
func (this *MetaFile) FileHeaderUnsafe(hash string) (header *FileHeader, ok bool) {
2024-04-27 20:11:50 +08:00
lazyHeader, ok := this.headerMap[hash]
if ok {
var err error
header, err = lazyHeader.FileHeaderUnsafe()
if err != nil {
ok = false
}
}
return
}
2024-04-26 18:44:29 +08:00
func (this *MetaFile) CloneFileHeader(hash string) (header *FileHeader, ok bool) {
this.mu.RLock()
defer this.mu.RUnlock()
2024-04-27 20:11:50 +08:00
lazyHeader, ok := this.headerMap[hash]
if !ok {
return
}
2024-04-27 20:11:50 +08:00
var err error
header, err = lazyHeader.FileHeaderUnsafe()
if err != nil {
ok = false
return
}
header = header.Clone()
return
}
2024-04-27 20:11:50 +08:00
func (this *MetaFile) FileHeaders() map[string]*LazyFileHeader {
this.mu.RLock()
defer this.mu.RUnlock()
return this.headerMap
}
2024-04-26 18:44:29 +08:00
func (this *MetaFile) ExistFile(hash string) bool {
this.mu.RLock()
defer this.mu.RUnlock()
_, ok := this.headerMap[hash]
return ok
}
// Compact the meta file
// TODO 考虑自动Compact的时机脏数据比例
func (this *MetaFile) Compact() error {
this.mu.Lock()
defer this.mu.Unlock()
var buf = bytes.NewBuffer(nil)
2024-04-27 20:11:50 +08:00
for hash, lazyHeader := range this.headerMap {
header, err := lazyHeader.FileHeaderUnsafe()
if err != nil {
return err
}
blockBytes, err := header.Encode(hash)
if err != nil {
return err
}
buf.Write(blockBytes)
}
2024-04-27 07:09:14 +08:00
AckWriteThread()
err := this.fp.Truncate(int64(buf.Len()))
2024-04-27 07:09:14 +08:00
ReleaseWriteThread()
if err != nil {
return err
}
2024-04-27 07:09:14 +08:00
AckReadThread()
_, err = this.fp.Seek(0, io.SeekStart)
2024-04-27 07:09:14 +08:00
ReleaseReadThread()
if err != nil {
return err
}
2024-04-27 07:09:14 +08:00
AckWriteThread()
_, err = this.fp.Write(buf.Bytes())
2024-04-27 07:09:14 +08:00
ReleaseWriteThread()
this.isModified = true
return err
}
func (this *MetaFile) SyncUnsafe() error {
if !this.isModified {
return nil
}
2024-04-27 07:09:14 +08:00
AckWriteThread()
err := this.fp.Sync()
2024-04-27 07:09:14 +08:00
ReleaseWriteThread()
if err != nil {
return err
}
for hash := range this.modifiedHashMap {
2024-04-27 20:11:50 +08:00
lazyHeader, ok := this.headerMap[hash]
if ok {
2024-04-27 20:11:50 +08:00
header, decodeErr := lazyHeader.FileHeaderUnsafe()
if decodeErr != nil {
return decodeErr
}
header.IsWriting = false
}
}
this.isModified = false
this.modifiedHashMap = map[string]zero.Zero{}
return nil
}
2024-04-26 18:44:29 +08:00
// Close 关闭当前文件
func (this *MetaFile) Close() error {
return this.fp.Close()
}
// RemoveAll 删除所有数据
func (this *MetaFile) RemoveAll() error {
_ = this.fp.Close()
return os.Remove(this.fp.Name())
}