-
Notifications
You must be signed in to change notification settings - Fork 113
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
xattrs: use unix flocks when writing multiple xattrs (#2528)
* xattrs: use unix flocks when writing multiple xattrs Signed-off-by: Jörn Friedrich Dreyer <[email protected]> * Implement locking of files when setting and reading xattrs To lock, a file with the ending .flock is created beside the to be locked node (which also can be a directory) which is locked with a Lock. Other ocis processes respect that. * Improve error handling of the xattr functions handling multiple data. * Move file lock functions to their own module. * Fix doc comments of exported funcs * Return err instead of nil to get error from the defer func. Co-authored-by: David Christofas <[email protected]> * Wait if a file is locked and make up to ten attempts. * start for loop with i=1 to have a proper factor for the wait period. * return error Co-authored-by: David Christofas <[email protected]> Co-authored-by: Klaas Freitag <[email protected]> Co-authored-by: David Christofas <[email protected]> Co-authored-by: David Christofas <[email protected]>
- Loading branch information
1 parent
2c8ec9c
commit 6901ae6
Showing
5 changed files
with
239 additions
and
28 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
Enhancement: use an exclcusive write lock when writing multiple attributes | ||
|
||
The xattr package can use an exclusive write lock when writing multiple extended attributes | ||
|
||
https://github.com/cs3org/reva/pull/2528 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
// Copyright 2018-2021 CERN | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
// | ||
// In applying this license, CERN does not waive the privileges and immunities | ||
// granted to it by virtue of its status as an Intergovernmental Organization | ||
// or submit itself to any jurisdiction. | ||
|
||
package filelocks | ||
|
||
import ( | ||
"errors" | ||
"os" | ||
"time" | ||
|
||
"github.com/gofrs/flock" | ||
) | ||
|
||
// FlockFile returns the flock filename for a given file name | ||
// it returns an empty string if the input is empty | ||
func FlockFile(file string) string { | ||
var n string | ||
if len(file) > 0 { | ||
n = file + ".flock" | ||
} | ||
return n | ||
} | ||
|
||
// acquireWriteLog acquires a lock on a file or directory. | ||
// if the parameter write is true, it gets an exclusive write lock, otherwise a shared read lock. | ||
// The function returns a Flock object, unlocking has to be done in the calling function. | ||
func acquireLock(file string, write bool) (*flock.Flock, error) { | ||
var err error | ||
|
||
// Create a file to carry the log | ||
n := FlockFile(file) | ||
if len(n) == 0 { | ||
return nil, errors.New("lock path is empty") | ||
} | ||
// Acquire the write log on the target node first. | ||
lock := flock.New(n) | ||
|
||
var ok bool | ||
for i := 1; i <= 10; i++ { | ||
if write { | ||
ok, err = lock.TryLock() | ||
} else { | ||
ok, err = lock.TryRLock() | ||
} | ||
|
||
if ok { | ||
break | ||
} | ||
|
||
time.Sleep(time.Duration(i*3) * time.Millisecond) | ||
} | ||
|
||
if !ok { | ||
err = errors.New("could not acquire lock after wait") | ||
} | ||
|
||
if err != nil { | ||
return nil, err | ||
} | ||
return lock, nil | ||
} | ||
|
||
// AcquireReadLock tries to acquire a shared lock to read from the | ||
// file and returns a lock object or an error accordingly. | ||
func AcquireReadLock(file string) (*flock.Flock, error) { | ||
return acquireLock(file, false) | ||
} | ||
|
||
// AcquireWriteLock tries to acquire a shared lock to write from the | ||
// file and returns a lock object or an error accordingly. | ||
func AcquireWriteLock(file string) (*flock.Flock, error) { | ||
return acquireLock(file, true) | ||
} | ||
|
||
// ReleaseLock releases a lock from a file that was previously created | ||
// by AcquireReadLock or AcquireWriteLock. | ||
func ReleaseLock(lock *flock.Flock) error { | ||
// there is a probability that if the file can not be unlocked, | ||
// we also can not remove the file. We will only try to remove if it | ||
// was successfully unlocked. | ||
err := lock.Unlock() | ||
if err == nil { | ||
err = os.Remove(lock.Path()) | ||
} | ||
return err | ||
} |