Skip to content
Snippets Groups Projects
Commit 03b84df8 authored by Rob Swindell's avatar Rob Swindell :speech_balloon:
Browse files

Add/use xp_lockfile() to support blocking file range/region lock acquisition

Under heavy loads, I've found periodic non-blocking lock attempts just aren't
reliable enough: in particular, on Vertrauen, the guest user account record
in the user.tab file gets read and written-to A LOT (updating stats), and
under heavy loads (especially with hundreds of web client sessions), I'd get
timeouts attempting to lock the guest record in the user.tab (after about a
minute of periodic retries) - so let's just block "forever" to get the user
record lock (or until signaled or notified of a deadlock). With this change,
I've not had any user.tab lock errors or apparent deadlocks.

Let the underlying OS/filesystem handle queuing and deadlock detection,
when supported. lock() still behaves as before: non-blocking lock attempt.
parent b422688e
No related branches found
No related tags found
No related merge requests found
......@@ -283,12 +283,7 @@ bool lockuserdat(int file, unsigned user_number)
off_t offset = userdatoffset(user_number);
unsigned attempt=0;
while(attempt < LOOP_USERDAT && lock(file, offset, USER_RECORD_LINE_LEN) == -1) {
attempt++;
RETRY_DELAY(attempt);
}
return attempt < LOOP_USERDAT;
return xp_lockfile(file, offset, USER_RECORD_LINE_LEN, /* block: */true) == 0;
}
bool unlockuserdat(int file, unsigned user_number)
......
......@@ -83,13 +83,15 @@ off_t filelength(int fd)
#if defined F_OFD_SETLK
#undef F_SETLK
#define F_SETLK F_OFD_SETLK
#undef F_SETLKW
#define F_SETLKW F_OFD_SETLKW
#else
#warning Linux OFD locks not enabled!
#endif
#endif
/* Sets a lock on a portion of a file */
int lock(int fd, off_t pos, off_t len)
int xp_lockfile(int fd, off_t pos, off_t len, bool block)
{
#if defined USE_FCNTL_LOCKS
struct flock alock = {0};
......@@ -106,12 +108,15 @@ int lock(int fd, off_t pos, off_t len)
alock.l_start = pos;
alock.l_len = (int)len;
int result = fcntl(fd, F_SETLK, &alock);
int result = fcntl(fd, block ? F_SETLKW : F_SETLK, &alock);
if(result == -1 && errno != EINVAL)
return -1;
#elif !defined(__QNX__) && !defined(__solaris__)
int op = LOCK_EX;
if(!block)
op |= LOCK_NB;
/* use flock (doesn't work over NFS) */
if(flock(fd,LOCK_EX|LOCK_NB)!=0 && errno != EOPNOTSUPP)
if(flock(fd, op) != 0 && errno != EOPNOTSUPP)
return(-1);
#endif
return(0);
......@@ -244,15 +249,17 @@ int sopen(const char *fn, int sh_access, int share, ...)
#define LK_UNLCK LK_UNLOCK
#endif
int lock(int file, off_t offset, off_t size)
int xp_lockfile(int file, off_t offset, off_t size, bool block)
{
int i;
off_t pos;
pos=tell(file);
if(offset!=pos)
(void)lseek(file, offset, SEEK_SET);
i=_locking(file,LK_NBLCK,(long)size);
do {
i = _locking(file, block ? LK_LOCK : LK_NBLCK, (long)size);
} while(block && i != 0 && errno = EDEADLOCK);
if(offset!=pos)
(void)lseek(file, pos, SEEK_SET);
return(i);
......@@ -262,7 +269,7 @@ int unlock(int file, off_t offset, off_t size)
{
int i;
off_t pos;
pos=tell(file);
if(offset!=pos)
(void)lseek(file, offset, SEEK_SET);
......@@ -274,6 +281,11 @@ int unlock(int file, off_t offset, off_t size)
#endif /* !__unix__ && (_MSC_VER || __MINGW32__ || __DMC__) */
int lock(int fd, off_t pos, off_t len)
{
return xp_lockfile(fd, pos, len, /* block */false);
}
#if defined(_WIN32 )
static size_t
p2roundup(size_t n)
......
......@@ -156,6 +156,7 @@ extern "C" {
#endif
#if !defined(__BORLANDC__) && !defined(__WATCOMC__)
DLLEXPORT int xp_lockfile(int fd, off_t pos, off_t len, bool block);
DLLEXPORT int lock(int fd, off_t pos, off_t len);
DLLEXPORT int unlock(int fd, off_t pos, off_t len);
#endif
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment