Ignore:
Timestamp:
Mar 18, 2016, 7:53:30 PM (9 years ago)
Author:
Silvan Scherrer
Message:

tdb: Use DosSetFileLocks directly for db locks.

This is to overcome some fcntl() API incompleteness in kLIBC
(like inability to upgrade locks or join adjacent lock regions
into one). It made the torture test run a bit better but there
are still two major problems both coming from DosSetFileLocks
impl (which fcntl() is currently based upon too): a) inability to
detect deadlocks and b) missing atomic unlock/lock support if
unlock/lock regions don't match.

With the current implementation, tdborture works fine for 1 or 2
worker processes but hangs when there are 3 or more. [Before that,
it would only work with 1 process and would likely to corrupt
the database and terminate if there were 2 or more processes].

Author: Dmitriy Kuminov (@dmik).

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/server/lib/tdb/common/io.c

    r878 r895  
    9191                return -1;
    9292
    93 #ifdef __OS2__
    94         // YD we must upgrade read locks to write locks (exclusive), as otherwise
    95         // the owner (us) is not allowed to write to the file (different from unix)
    96         // if a wider previous lock is in effect, we cannot write lock our segment
    97         // (e.g. a lock_upgrade locks all the file), so we hope the previous lock
    98         // is a write lock: do not wait for lock.
    99         // so this is what we try here:
    100         // 1. add a write lock and see it it works
    101         // 2. if the write lock wasn't set, we try to unlock the segment
    102         //    first and add the write lock afterwards
    103         // 3. we remove the write lock further down
    104         // 4. we add the removed lock from step #2 again
    105         int upgradeLockRC = 0;
    106         int unlockRC = -1;
    107         upgradeLockRC = tdb_brlock(tdb, F_WRLCK, off, len, TDB_LOCK_NOWAIT);
    108         if (upgradeLockRC != 0) {
    109                 unlockRC = tdb_brunlock(tdb, F_RDLCK, off, 1);
    110                 upgradeLockRC = tdb_brlock(tdb, F_WRLCK, off, len, TDB_LOCK_NOWAIT);
    111         }
    112         // no need to log a successful upgrade
    113         if (upgradeLockRC != 0)
    114         TDB_LOG((tdb, TDB_DEBUG_TRACE,"upgrading lock at %d len=%d "
    115                 "before writing %s (rc=%d).\n", off, len,
    116                  upgradeLockRC ? "failed":"was successful", upgradeLockRC));
    117 #endif
    11893        if (tdb->map_ptr) {
    11994                memcpy(off + (char *)tdb->map_ptr, buf, len);
     
    141116                                 "write %d bytes at %d in two attempts\n",
    142117                                 len, off));
    143 #ifdef __OS2__ // remove our lock, if upgrade succeded
    144                         if (upgradeLockRC == 0)
    145                                 tdb_brunlock( tdb, F_WRLCK, off, len);
    146                         if (unlockRC == 0)
    147                                 tdb_brlock( tdb, F_RDLCK, off, 1, TDB_LOCK_WAIT);
    148 #endif
    149                         return -1;
    150                 }
    151         }
    152 #ifdef __OS2__ // remove our lock, if upgrade succeded
    153         if (upgradeLockRC == 0)
    154                 tdb_brunlock( tdb, F_WRLCK, off, len);
    155         if (unlockRC == 0)
    156                 tdb_brlock( tdb, F_RDLCK, off, 1, TDB_LOCK_WAIT);
    157 #endif
     118                        return -1;
     119                }
     120        }
    158121        return 0;
    159122}
Note: See TracChangeset for help on using the changeset viewer.