finally got rid of the race-conditions (Usability will be fixed later)

This commit is contained in:
knoxfighter 2017-10-30 00:44:05 +01:00
parent 5703a22544
commit 8179e2c917
3 changed files with 91 additions and 31 deletions

View File

@ -5,6 +5,8 @@ import (
"path"
"os"
"log"
"errors"
"time"
)
type FileLock struct {
@ -17,8 +19,13 @@ type Lock struct {
Write int
}
func newLock() FileLock {
lock := FileLock{}
var ErrorLocking error = errors.New("error locking file")
var ErrorAlreadyLocked error = errors.New("file already locke by another routine")
func NewLock() FileLock {
lock := FileLock{
Locks: make(map[string]Lock),
}
return lock
}
@ -36,70 +43,103 @@ func makeAbsolutePath(target string) string {
return path.Join(wd, target)
}
func (fl *FileLock) Lock(path string) {
func (fl *FileLock) Lock(filePath string) error {
fl.m.Lock()
defer fl.m.Unlock()
path = makeAbsolutePath(path)
filePath = makeAbsolutePath(filePath)
if fl.Locks[path].Read == 0 && fl.Locks[path].Write == 0 {
lock := fl.Locks[path]
if fl.Locks[filePath].Read == 0 && fl.Locks[filePath].Write == 0 {
lock := fl.Locks[filePath]
lock.Write = 1
fl.Locks[path] = lock
fl.Locks[filePath] = lock
} else {
return ErrorAlreadyLocked
}
log.Println("write locked")
return nil
}
func (fl *FileLock) Unlock(path string) {
func (fl *FileLock) Unlock(filePath string) error {
fl.m.Lock()
defer fl.m.Unlock()
path = makeAbsolutePath(path)
filePath = makeAbsolutePath(filePath)
lock := fl.Locks[path]
lock := fl.Locks[filePath]
if lock.Read == 0 && lock.Write == 1 {
lock.Write = 0
fl.Locks[path] = lock
fl.Locks[filePath] = lock
} else {
return ErrorAlreadyLocked
}
log.Println("write unlocked")
return nil
}
func (fl *FileLock) RLock(path string) {
func (fl *FileLock) RLock(filePath string) error {
fl.m.Lock()
defer fl.m.Unlock()
path = makeAbsolutePath(path)
filePath = makeAbsolutePath(filePath)
lock := fl.Locks[path]
lock := fl.Locks[filePath]
if lock.Write == 0 {
lock.Read++
fl.Locks[path] = lock
fl.Locks[filePath] = lock
} else {
return ErrorAlreadyLocked
}
log.Println("read locked")
return nil
}
func (fl *FileLock) RUnlock(path string) {
func (fl *FileLock) RUnlock(filePath string) error {
fl.m.Lock()
defer fl.m.Unlock()
path = makeAbsolutePath(path)
filePath = makeAbsolutePath(filePath)
lock := fl.Locks[path]
lock := fl.Locks[filePath]
if lock.Read > 0 && lock.Write == 0 {
lock.Read--
fl.Locks[path] = lock
fl.Locks[filePath] = lock
} else {
return ErrorAlreadyLocked
}
log.Println("read unlocked")
return nil
}
func (fl *FileLock) LockW(path string) {
func (fl *FileLock) LockW(filePath string) {
log.Println("LockW called")
for {
err := fl.Lock(filePath)
log.Println(err)
if err == ErrorAlreadyLocked {
time.Sleep(time.Second * 2)
log.Println("file locked wait two seconds to access write-lock")
}
if err == nil {
break
}
}
return
}
func (fl *FileLock) UnlockW(path string) {
return
}
func (fl *FileLock) RLockW(filePath string) {
for {
err := fl.RLock(filePath)
func (fl *FileLock) RLockW(path string) {
return
}
if err == ErrorAlreadyLocked {
time.Sleep(time.Second * 2)
log.Println("file locked wait two seconds to access read-lock")
}
func (fl *FileLock) RUnlockW(path string) {
if err == nil {
break
}
}
return
}

View File

@ -26,7 +26,7 @@ type ModsResultList struct {
ModsResult []ModsResult `json:"mods"`
}
var fileLock lockfile.FileLock = lockfile.newLock()
var fileLock lockfile.FileLock = lockfile.NewLock()
func newMods(destination string) (Mods, error) {
var err error

View File

@ -9,6 +9,7 @@ import (
"archive/zip"
"errors"
"io"
"lockfile"
)
type ModInfoList struct {
@ -44,6 +45,16 @@ func (mod_info_list *ModInfoList) listInstalledMods() (error) {
err = filepath.Walk(mod_info_list.Destination, func(path string, info os.FileInfo, err error) error {
if !info.IsDir() && filepath.Ext(path) == ".zip" {
err = fileLock.RLock(path)
if err != nil && err == lockfile.ErrorAlreadyLocked {
log.Println(err)
return nil
} else if err != nil {
log.Printf("error locking file: %s", err)
return err
}
defer fileLock.RUnlock(path)
zip_file, err := zip.OpenReader(path)
if err != nil {
log.Fatalln(err)
@ -77,8 +88,12 @@ func (mod_info_list *ModInfoList) deleteMod(mod_name string) (error) {
//search for mod, that should be deleted
for _, mod := range mod_info_list.Mods {
if mod.Name == mod_name {
filePath := mod_info_list.Destination + "/" + mod.FileName
fileLock.LockW(filePath)
//delete mod
err = os.Remove(mod_info_list.Destination + "/" + mod.FileName)
err = os.Remove(filePath)
fileLock.Unlock(filePath)
if err != nil {
log.Printf("ModInfoList ... error when deleting mod: %s", err)
return err
@ -134,26 +149,31 @@ func (mod_info_list *ModInfoList) createMod(mod_name string, file_name string, m
var err error
//save uploaded file
new_file, err := os.Create(mod_info_list.Destination + "/" + file_name)
filePath := mod_info_list.Destination + "/" + file_name
new_file, err := os.Create(filePath)
if err != nil {
log.Printf("error on creating new file - %s: %s", file_name, err)
return err
}
defer new_file.Close()
fileLock.LockW(filePath)
_, err = io.Copy(new_file, mod_file)
if err != nil {
log.Printf("error on copying file to disk: %s", err)
return err
}
//reload the list
err = new_file.Close()
if err != nil {
log.Printf("error on closing new created zip-file: %s", err)
return err
}
fileLock.Unlock(filePath)
//reload the list
err = mod_info_list.listInstalledMods()
if err != nil {
log.Printf("error on listing mod-infos: %s", err)