add mutexes for concurrency, added concurrency tests
This commit is contained in:
parent
9cc659b973
commit
e3d512edcc
4 changed files with 52 additions and 1 deletions
|
@ -5,7 +5,7 @@ A golang library for extracting and creating archives.
|
||||||
|
|
||||||
## Roadmap
|
## Roadmap
|
||||||
- [ ] Automatically detect the archive format
|
- [ ] Automatically detect the archive format
|
||||||
- [ ] Add mutexes to work with concurrency
|
- [x] Add mutexes to work with concurrency
|
||||||
|
|
||||||
## Supported Formats
|
## Supported Formats
|
||||||
- `.tar.gz`
|
- `.tar.gz`
|
||||||
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
"io/fs"
|
"io/fs"
|
||||||
"os"
|
"os"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Type string
|
type Type string
|
||||||
|
@ -36,6 +37,7 @@ type Archive struct {
|
||||||
tarReader *tar.Reader // Used for anything with .tar due to how tar.Reader cannot be reset.
|
tarReader *tar.Reader // Used for anything with .tar due to how tar.Reader cannot be reset.
|
||||||
files map[string]*File
|
files map[string]*File
|
||||||
archiveFile *bytes.Reader
|
archiveFile *bytes.Reader
|
||||||
|
mu sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
// Filesystem represents a standard interface for filesystems.
|
// Filesystem represents a standard interface for filesystems.
|
||||||
|
@ -109,6 +111,8 @@ type File struct {
|
||||||
// It takes the path of the file in the Archive as its parameter.
|
// It takes the path of the file in the Archive as its parameter.
|
||||||
// The function returns ArchiveFile and an error, if any.
|
// The function returns ArchiveFile and an error, if any.
|
||||||
func (a *Archive) GetFile(path string) (*File, error) {
|
func (a *Archive) GetFile(path string) (*File, error) {
|
||||||
|
a.mu.Lock()
|
||||||
|
defer a.mu.Unlock()
|
||||||
file, ok := a.files[path]
|
file, ok := a.files[path]
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, ErrArchiveFileNotFound
|
return nil, ErrArchiveFileNotFound
|
||||||
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"sync"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -19,6 +20,43 @@ const (
|
||||||
|
|
||||||
var archiveRegex = regexp.MustCompile(`(?m)test[1|5]`)
|
var archiveRegex = regexp.MustCompile(`(?m)test[1|5]`)
|
||||||
|
|
||||||
|
func TestArchiveConcurrency(t *testing.T) {
|
||||||
|
err := os.MkdirAll(testArchiveBaseDir, os.ModePerm)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
testGenerateZip(t)
|
||||||
|
|
||||||
|
archive, err := Open(Zip, testArchiveBaseDir+"/test.zip")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
|
||||||
|
// Slam it, see if it breaks.
|
||||||
|
for _ = range 100_000 {
|
||||||
|
go func() {
|
||||||
|
wg.Add(1)
|
||||||
|
defer wg.Done()
|
||||||
|
file, err := archive.GetFile("test0.txt")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, "test0.txt", file.FileName)
|
||||||
|
|
||||||
|
err = file.Extract(ExtractFileOptions{
|
||||||
|
Overwrite: true,
|
||||||
|
Folder: testArchiveBaseDir + "/extracted/zip",
|
||||||
|
})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
wg.Wait()
|
||||||
|
|
||||||
|
err = os.RemoveAll(testArchiveBaseDir + "/extracted")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
err = archive.Close()
|
||||||
|
assert.NoError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
func TestArchiveExtract(t *testing.T) {
|
func TestArchiveExtract(t *testing.T) {
|
||||||
err := os.MkdirAll(testArchiveBaseDir, os.ModePerm)
|
err := os.MkdirAll(testArchiveBaseDir, os.ModePerm)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
@ -59,6 +97,9 @@ func TestArchiveExtract(t *testing.T) {
|
||||||
})
|
})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
err = os.RemoveAll(testArchiveBaseDir + "/extracted")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestArchiveZip(t *testing.T) {
|
func TestArchiveZip(t *testing.T) {
|
||||||
|
|
|
@ -22,6 +22,9 @@ type extractOptions struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func extract(filesystem Filesystem, opts ExtractOptions, archive *Archive) error {
|
func extract(filesystem Filesystem, opts ExtractOptions, archive *Archive) error {
|
||||||
|
archive.mu.Lock()
|
||||||
|
defer archive.mu.Unlock()
|
||||||
|
|
||||||
if filesystem.billyFS == nil {
|
if filesystem.billyFS == nil {
|
||||||
filesystem.file = true
|
filesystem.file = true
|
||||||
}
|
}
|
||||||
|
@ -55,6 +58,9 @@ func extract(filesystem Filesystem, opts ExtractOptions, archive *Archive) error
|
||||||
}
|
}
|
||||||
|
|
||||||
func extractFile(filesystem Filesystem, opts ExtractFileOptions, file *File) error {
|
func extractFile(filesystem Filesystem, opts ExtractFileOptions, file *File) error {
|
||||||
|
file.archive.mu.Lock()
|
||||||
|
defer file.archive.mu.Unlock()
|
||||||
|
|
||||||
if filesystem.billyFS == nil {
|
if filesystem.billyFS == nil {
|
||||||
filesystem.file = true
|
filesystem.file = true
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue