mirror of
				https://github.com/TeaOSLab/EdgeNode.git
				synced 2025-11-04 16:00: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