Skip to content

Commit 3802224

Browse files
authored
Merge pull request #371 from IBM-Cloud/dev
Fix: Excluding Windows `GOOS` from `flock` file mutex logic
2 parents 9cca421 + 6394821 commit 3802224

File tree

2 files changed

+42
-6
lines changed

2 files changed

+42
-6
lines changed

bluemix/configuration/persistor.go

Lines changed: 41 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import (
55
"io/ioutil"
66
"os"
77
"path/filepath"
8+
"runtime"
9+
"strings"
810
"time"
911

1012
"github.com/IBM-Cloud/ibm-cloud-cli-sdk/common/file_helpers"
@@ -31,28 +33,39 @@ type DiskPersistor struct {
3133
filePath string
3234
fileLock *flock.Flock
3335
parentContext context.Context
36+
runtimeGOOS string
3437
}
3538

3639
func NewDiskPersistor(path string) DiskPersistor {
3740
return DiskPersistor{
3841
filePath: path,
3942
fileLock: flock.New(path),
4043
parentContext: context.Background(),
44+
runtimeGOOS: runtime.GOOS,
4145
}
4246
}
4347

4448
func (dp DiskPersistor) Exists() bool {
4549
return file_helpers.FileExists(dp.filePath)
4650
}
4751

52+
func (dp *DiskPersistor) windowsLockedRead(data DataInterface) error {
53+
// TO DO: exclusive file-locking for the reading NOT yet implemented
54+
return dp.read(data)
55+
}
56+
57+
func isBlockingLockError(err error) bool {
58+
return err != nil && !strings.Contains(err.Error(), "no such file or directory")
59+
}
60+
4861
func (dp *DiskPersistor) lockedRead(data DataInterface) error {
4962
lockCtx, cancelLockCtx := context.WithTimeout(dp.parentContext, 30*time.Second) /* allotting a 30-second timeout means there can be a maximum of 298 failed retrials (each up to 500 ms, as
5063
specified after the deferred call to cancelLockCtx). 30 appears to be a conventional value for a parent context passed to TryLockContext, as per docs */
5164
defer cancelLockCtx()
5265
_, lockErr := dp.fileLock.TryLockContext(lockCtx, 100*time.Millisecond) /* provide a file lock just while dp.read is called, because it calls an unmarshaling function
5366
The boolean (first return value) can be wild-carded because lockErr must be non-nil when the lock-acquiring fails (whereby the boolean will be false) */
5467
defer dp.fileLock.Unlock()
55-
if lockErr != nil {
68+
if isBlockingLockError(lockErr) {
5669
return lockErr
5770
}
5871
readErr := dp.read(data)
@@ -62,26 +75,49 @@ func (dp *DiskPersistor) lockedRead(data DataInterface) error {
6275
return nil
6376
}
6477

78+
func (dp DiskPersistor) readWithFileLock(data DataInterface) error {
79+
switch dp.runtimeGOOS {
80+
case "windows":
81+
return dp.windowsLockedRead(data)
82+
default:
83+
return dp.lockedRead(data)
84+
}
85+
}
86+
87+
func (dp DiskPersistor) writeWithFileLock(data DataInterface) error {
88+
switch dp.runtimeGOOS {
89+
case "windows":
90+
return dp.windowsLockedWrite(data)
91+
default:
92+
return dp.lockedWrite(data)
93+
}
94+
}
95+
6596
func (dp DiskPersistor) Load(data DataInterface) error {
66-
err := dp.lockedRead(data)
97+
err := dp.readWithFileLock(data)
6798
if os.IsPermission(err) {
6899
return err
69100
}
70101

71102
if err != nil { /* would happen if there was nothing to read (EOF) */
72-
err = dp.lockedWrite(data)
103+
err = dp.writeWithFileLock(data)
73104
}
74105
return err
75106
}
76107

108+
func (dp *DiskPersistor) windowsLockedWrite(data DataInterface) error {
109+
// TO DO: exclusive file-locking for the writing NOT yet implemented
110+
return dp.write(data)
111+
}
112+
77113
func (dp DiskPersistor) lockedWrite(data DataInterface) error {
78114
lockCtx, cancelLockCtx := context.WithTimeout(dp.parentContext, 30*time.Second) /* allotting a 30-second timeout means there can be a maximum of 298 failed retrials (each up to 500 ms, as
79115
specified after the deferred call to cancelLockCtx). 30 appears to be a conventional value for a parent context passed to TryLockContext, as per docs */
80116
defer cancelLockCtx()
81117
_, lockErr := dp.fileLock.TryLockContext(lockCtx, 100*time.Millisecond) /* provide a file lock just while dp.read is called, because it calls an unmarshaling function
82118
The boolean (first return value) can be wild-carded because lockErr must be non-nil when the lock-acquiring fails (whereby the boolean will be false) */
83119
defer dp.fileLock.Unlock()
84-
if lockErr != nil {
120+
if isBlockingLockError(lockErr) {
85121
return lockErr
86122
}
87123
writeErr := dp.write(data)
@@ -92,7 +128,7 @@ func (dp DiskPersistor) lockedWrite(data DataInterface) error {
92128
}
93129

94130
func (dp DiskPersistor) Save(data DataInterface) error {
95-
return dp.lockedWrite(data)
131+
return dp.writeWithFileLock(data)
96132
}
97133

98134
func (dp DiskPersistor) read(data DataInterface) error {

bluemix/version.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ package bluemix
33
import "fmt"
44

55
// Version is the SDK version
6-
var Version = VersionType{Major: 1, Minor: 0, Build: 2}
6+
var Version = VersionType{Major: 1, Minor: 0, Build: 3}
77

88
// VersionType describe version info
99
type VersionType struct {

0 commit comments

Comments
 (0)