mirror of
https://github.com/TeaOSLab/EdgeNode.git
synced 2025-11-03 23:20:25 +08:00
bfs:同一个Hash同时只能有一个Writer,避免多线程读冲突
This commit is contained in:
@@ -5,6 +5,7 @@ package bfs
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/TeaOSLab/EdgeNode/internal/zero"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
@@ -31,8 +32,9 @@ type BlocksFile struct {
|
|||||||
|
|
||||||
mu *sync.RWMutex
|
mu *sync.RWMutex
|
||||||
|
|
||||||
writtenBytes int64
|
writtenBytes int64
|
||||||
syncAt time.Time
|
writingFileMap map[string]zero.Zero // hash => Zero
|
||||||
|
syncAt time.Time
|
||||||
|
|
||||||
readerPool chan *FileReader
|
readerPool chan *FileReader
|
||||||
}
|
}
|
||||||
@@ -64,12 +66,13 @@ func NewBlocksFileWithRawFile(fp *os.File, options *BlockFileOptions) (*BlocksFi
|
|||||||
}
|
}
|
||||||
|
|
||||||
return &BlocksFile{
|
return &BlocksFile{
|
||||||
fp: fp,
|
fp: fp,
|
||||||
mFile: mFile,
|
mFile: mFile,
|
||||||
mu: mu,
|
mu: mu,
|
||||||
opt: options,
|
opt: options,
|
||||||
syncAt: time.Now(),
|
syncAt: time.Now(),
|
||||||
readerPool: make(chan *FileReader, 32),
|
readerPool: make(chan *FileReader, 32),
|
||||||
|
writingFileMap: map[string]zero.Zero{},
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -102,8 +105,6 @@ func (this *BlocksFile) Write(hash string, blockType BlockType, b []byte, origin
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO 实现 originOffset
|
|
||||||
|
|
||||||
this.mu.Lock()
|
this.mu.Lock()
|
||||||
defer this.mu.Unlock()
|
defer this.mu.Unlock()
|
||||||
|
|
||||||
@@ -144,11 +145,16 @@ func (this *BlocksFile) OpenFileWriter(fileHash string, bodySize int64, isPartia
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO 限制对同一个Hash同时只能有一个Writer
|
|
||||||
|
|
||||||
this.mu.Lock()
|
this.mu.Lock()
|
||||||
defer this.mu.Unlock()
|
defer this.mu.Unlock()
|
||||||
|
|
||||||
|
_, isWriting := this.writingFileMap[fileHash]
|
||||||
|
if isWriting {
|
||||||
|
err = ErrFileIsWriting
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.writingFileMap[fileHash] = zero.Zero{}
|
||||||
|
|
||||||
err = this.checkStatus()
|
err = this.checkStatus()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
@@ -304,6 +310,12 @@ func (this *BlocksFile) TestReaderPool() chan *FileReader {
|
|||||||
return this.readerPool
|
return this.readerPool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (this *BlocksFile) removeWritingFile(hash string) {
|
||||||
|
this.mu.Lock()
|
||||||
|
delete(this.writingFileMap, hash)
|
||||||
|
this.mu.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
func (this *BlocksFile) checkStatus() error {
|
func (this *BlocksFile) checkStatus() error {
|
||||||
if this.isClosed {
|
if this.isClosed {
|
||||||
return ErrClosed
|
return ErrClosed
|
||||||
|
|||||||
@@ -8,6 +8,32 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func TestBlocksFile_OpenFileWriter_SameHash(t *testing.T) {
|
||||||
|
bFile, openErr := bfs.OpenBlocksFile("testdata/test.b", bfs.DefaultBlockFileOptions)
|
||||||
|
if openErr != nil {
|
||||||
|
if os.IsNotExist(openErr) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
t.Fatal(openErr)
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
writer, err := bFile.OpenFileWriter(bfs.Hash("123456"), -1, false)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
_ = writer.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
writer, err := bFile.OpenFileWriter(bfs.Hash("123456"), -1, false)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
_ = writer.Close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestBlocksFile_RemoveAll(t *testing.T) {
|
func TestBlocksFile_RemoveAll(t *testing.T) {
|
||||||
bFile, err := bfs.OpenBlocksFile("testdata/test.b", bfs.DefaultBlockFileOptions)
|
bFile, err := bfs.OpenBlocksFile("testdata/test.b", bfs.DefaultBlockFileOptions)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -16,6 +42,9 @@ func TestBlocksFile_RemoveAll(t *testing.T) {
|
|||||||
}
|
}
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
defer func() {
|
||||||
|
_ = bFile.Close()
|
||||||
|
}()
|
||||||
|
|
||||||
err = bFile.RemoveAll()
|
err = bFile.RemoveAll()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -79,6 +79,10 @@ func (this *FileWriter) WriteBodyAt(b []byte, offset int64) (n int, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (this *FileWriter) Close() error {
|
func (this *FileWriter) Close() error {
|
||||||
|
defer func() {
|
||||||
|
this.bFile.removeWritingFile(this.hash)
|
||||||
|
}()
|
||||||
|
|
||||||
if !this.isPartial && !this.hasMeta {
|
if !this.isPartial && !this.hasMeta {
|
||||||
return errors.New("no meta found")
|
return errors.New("no meta found")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -95,8 +95,6 @@ func (this *FS) OpenFileWriter(hash string, bodySize int64, isPartial bool) (*Fi
|
|||||||
return nil, errors.New("invalid body size for partial content")
|
return nil, errors.New("invalid body size for partial content")
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO 限制同一个hash同时只能有一个Writer
|
|
||||||
|
|
||||||
bFile, err := this.openBFileForHashWriting(hash)
|
bFile, err := this.openBFileForHashWriting(hash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|||||||
@@ -233,6 +233,11 @@ func (this *MetaFile) FileHeader(hash string) (header *FileHeader, ok bool) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (this *MetaFile) FileHeaderUnsafe(hash string) (header *FileHeader, ok bool) {
|
||||||
|
header, ok = this.headerMap[hash]
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func (this *MetaFile) CloneFileHeader(hash string) (header *FileHeader, ok bool) {
|
func (this *MetaFile) CloneFileHeader(hash string) (header *FileHeader, ok bool) {
|
||||||
this.mu.RLock()
|
this.mu.RLock()
|
||||||
defer this.mu.RUnlock()
|
defer this.mu.RUnlock()
|
||||||
|
|||||||
Reference in New Issue
Block a user