Is a Java FileLock a POSIX advisory (fcntl) lock
Some Unix operating systems, including Linux, provide BSD-style (flock
) locks, so it might be thought that Java FileLock
could be implemented using BSD-style locks rather than POSIX locks. But that is not possible, because BSD-style locks are whole-file locks rather than record locks, and FileLock
is a record lock: each lock is for a range of bytes in a file. Thus there is no real choice on a Unix system, and assuming that the implementation of FileLock
uses POSIX fcntl
locks is a safe assumption on a Unix operating system.
The resulting FileLock
locks might or might not interact with BSD-style locks. BSD-style locks can be implemented using POSIX locks (this was the case for Linux before version 2.0), or the operating system might have the two styles of locking interact (this is the case for FreeBSD). But in general that can not be guaranteed, and BSD-style locks and Java locks might be effectively invisible to each other (this is the case for any version of Linux you are likely to encounter).
How safe is it to use Java FileLock?
Java FileLock
uses advisory (not mandatory) locks on many platforms. That means it may only provide locking against other applications that also use FileLock
(or the equivalent in other languages).
Neither Linux or Windows implement mandatory locking across the board. For instance:
For Linux and similar, file locking is advisory only.
For Windows, according to Wikipedia:
"For applications that use the file read/write APIs in Windows, byte-range locks are enforced .... by the file systems that execute
within Windows. For applications that use the file mapping APIs in
Windows, byte-range locks are not enforced ..."In other words, locking on Windows can be either mandatory or advisory, depending on which API an Windows application uses to access files.
How safe is it to use Java FileLock?
If you are actually asking if it is safe to assume that FileLock
provides mandatory file locking with respect to all other applications (Java & non-Java) irrespective of how they are written, the answer is No. It is NOT safe to make that assumption.
Is there a solution for locking a file appropriately in Java 6?
Only if all of the applications (Java & other) cooperate; e.g. by using FileLock
or the equivalent.
If you can't make that assumption, there is no solution using portable Java. Indeed, on most (if not all) common OS platforms, there is no solution at all, AFAIK ... because the platform itself doesn't support mandatory file locking independent of the application.
Are POSIX file locks reentrant?
Advisory locks through fcntl
are on a per process base and just accumulate locked intervals on the file for the given process. That is, it is up to the application to keep track of the intervals and any unlock call for an interval will unlock it, regardless on how many lock calls had been made for that interval.
Even worse, the closing of any file descriptor for the file cancels all locks on the file:
As well as being removed by an explicit F_UNLCK, record locks are
automatically released when the process terminates or if it closes any
file descriptor referring to a file on which locks are held. This is bad: it means that a process can lose the locks on a
file like
/etc/passwd or /etc/mtab when for some reason a library function decides to open, read and close it.
fcntl F_GETLK always returns F_UNLCK
You're misunderstanding the F_GETLK
query. It returns F_UNLCK
when nothing blocks the calling process from placing a lock of the given type at the given position.
Since the calling process is the one that created these existing locks, it can also create this new lock.
The Mac OS X manuals say
F_GETLK
Get the first lock that blocks the lock description pointed to by the third argument, arg,
taken as a pointer to a struct flock (see above). The information retrieved overwrites the
information passed to fcntl in the flock structure. If no lock is found that would prevent
this lock from being created, the structure is left unchanged by this function call except
for the lock type which is set toF_UNLCK
.
Linux IPC: Locking, but not file based locking
flock the directory itself — then you never need worry about where to put the lock file:
import errno
import fcntl
import os
import sys
# This will work on Linux
dirfd = os.open(THE_DIRECTORY, os.O_RDONLY) # FIXME: FD_CLOEXEC
try:
fcntl.flock(dirfd, fcntl.LOCK_EX|fcntl.LOCK_NB)
except IOError as ex:
if ex.errno != errno.EAGAIN:
raise
print "Somebody else is working here; quitting." # FIXME: logging
sys.exit(1)
do_the_work()
os.close(dirfd)
Fcntl in go doesn't work
If I create the file with touch lockfiletest.lock
, that is with no file contents, your program fails with your error: error locking file2: bad file descriptor
.
$ rm -f lockfiletest.lock
$ touch lockfiletest.lock
$ go run lockfiletest.go
2017/10/27 21:17:27 error locking file2: bad file descriptor
I changed the file open to closely match TestFcntlFlock
.
$ uname -s
Linux
~/go/src/syscall$ $ go test -v -run=TestFcntlFlock syscall_unix_test.go
=== RUN TestFcntlFlock
--- PASS: TestFcntlFlock (0.01s)
PASS
ok syscall 0.008s
~/go/src/syscall$
For example,
package main
import (
"io"
"log"
"os"
"syscall"
"time"
)
func main() {
time.Sleep(time.Second)
name := "lockfiletest.lock"
file, err := os.OpenFile(name, syscall.O_CREAT|syscall.O_RDWR|syscall.O_CLOEXEC, 0666)
if err != nil {
log.Printf("error opening file: %s", err)
return
}
defer file.Close()
flockT := syscall.Flock_t{
Type: syscall.F_WRLCK,
Whence: io.SeekStart,
Start: 0,
Len: 0,
}
err = syscall.FcntlFlock(file.Fd(), syscall.F_SETLK, &flockT)
if err != nil {
log.Printf("error locking file: %s", err)
return
}
log.Println("lock2 accessed")
time.Sleep(time.Second * 5)
log.Println("func2 finished")
time.Sleep(time.Second * 15)
}
Output:
$ rm -f lockfiletest.lock
$ touch lockfiletest.lock
$ go run lockfiletest.go
2017/10/27 21:21:56 lock2 accessed
2017/10/27 21:22:01 func2 finished
$ rm -f lockfiletest.lock
$ go run lockfiletest.go
2017/10/27 21:22:25 lock2 accessed
2017/10/27 21:22:30 func2 finished
$ go run lockfiletest.go
2017/10/27 21:25:40 lock2 accessed
2017/10/27 21:25:45 func2 finished
$
Related Topics
Connect to SQL Server from Linux via Jdbc Using Integratedsecurity (Windows Authentication)
Arval SQLexception: Fatal: Sorry, Too Many Clients Already in Postgres
Understand the R Class in Android
Firebase:Recycler View No Adater Attached , Skipping Layout
Tool for Creating a Java Daemon Service on Linux
Android - Span_Exclusive_Exclusive Spans Cannot Have a Zero Length
Java Jsch Changing User on Remote MAChine and Execute Command
Permission to Write to the Sd Card
Difference Between Using Java.Library.Path and Ld_Library_Path
Wait Until Firestore Data Is Retrieved to Launch an Activity
How to Kill a Linux Process in Java with Sigkill Process.Destroy() Does Sigterm
Wait Until Tomcat Finishes Starting Up
Read_External_Storage Permission for Android
Create a Java Executable with Eclipse