From 8fc06d9c794c704eed2ab8707768fc72cc677ded Mon Sep 17 00:00:00 2001 From: Andrew Branson Date: Mon, 12 May 2014 16:55:54 +0200 Subject: Tweak locks to hopefully avoid deadlocks a bit --- .../c2kernel/persistency/TransactionManager.java | 89 +++++++++++++--------- 1 file changed, 52 insertions(+), 37 deletions(-) (limited to 'src/main/java/com/c2kernel/persistency') diff --git a/src/main/java/com/c2kernel/persistency/TransactionManager.java b/src/main/java/com/c2kernel/persistency/TransactionManager.java index 86e8199..d966eec 100644 --- a/src/main/java/com/c2kernel/persistency/TransactionManager.java +++ b/src/main/java/com/c2kernel/persistency/TransactionManager.java @@ -63,16 +63,14 @@ public class TransactionManager { Integer sysKeyIntObj = new Integer(sysKey); // check to see if the locker has been modifying this cluster - synchronized(locks) { - if (locks.containsKey(sysKeyIntObj) && locks.get(sysKeyIntObj).equals(locker)) { - ArrayList lockerTransaction = pendingTransactions.get(locker); - for (TransactionEntry thisEntry : lockerTransaction) { - if (sysKey == thisEntry.sysKey.intValue() && path.equals(thisEntry.getPath())) { - if (thisEntry.obj == null) - throw new ClusterStorageException("ClusterStorageManager.get() - Cluster " + path + " has been deleted in " + sysKey + - " but not yet committed"); - return thisEntry.obj; - } + if (locks.containsKey(sysKeyIntObj) && locks.get(sysKeyIntObj).equals(locker)) { + ArrayList lockerTransaction = pendingTransactions.get(locker); + for (TransactionEntry thisEntry : lockerTransaction) { + if (sysKey == thisEntry.sysKey.intValue() && path.equals(thisEntry.getPath())) { + if (thisEntry.obj == null) + throw new ClusterStorageException("ClusterStorageManager.get() - Cluster " + path + " has been deleted in " + sysKey + + " but not yet committed"); + return thisEntry.obj; } } } @@ -85,6 +83,7 @@ public class TransactionManager { */ public void put(int sysKey, C2KLocalObject obj, Object locker) throws ClusterStorageException { Integer sysKeyIntObj = new Integer(sysKey); + Object tempLocker = null; ArrayList lockerTransaction; String path = ClusterStorage.getPath(obj); @@ -99,28 +98,35 @@ public class TransactionManager { throw new ClusterStorageException("ClusterStorageManager.get() - Access denied: Object " + sysKeyIntObj + " has been locked for writing by " + thisLocker); } - else { // either we are the locker, or there is no locker - if (locker == null) { // non-locking put/delete - storage.put(sysKeyIntObj, obj); - return; + else { // no locks for this item + if (locker == null) { // lock the item until the non-transactional put is complete :/ + tempLocker = new Object(); + locks.put(sysKeyIntObj, tempLocker); + lockerTransaction = null; } - else {// initialise the transaction + else { // initialise the transaction locks.put(sysKeyIntObj, locker); lockerTransaction = new ArrayList(); pendingTransactions.put(locker, lockerTransaction); } } - - // create the new entry in the transaction table - TransactionEntry newEntry = new TransactionEntry(sysKeyIntObj, path, obj); - /* equals() in TransactionEntry only compares sysKey and path, so we can use - * contains() in ArrayList to looks for preexisting entries for this cluster - * and overwrite them. - */ - if (lockerTransaction.contains(newEntry)) - lockerTransaction.remove(newEntry); - lockerTransaction.add(newEntry); } + + if (tempLocker != null) { // non-locking put/delete + storage.put(sysKeyIntObj, obj); + locks.remove(sysKeyIntObj); + return; + } + + // create the new entry in the transaction table + TransactionEntry newEntry = new TransactionEntry(sysKeyIntObj, path, obj); + /* equals() in TransactionEntry only compares sysKey and path, so we can use + * contains() in ArrayList to looks for preexisting entries for this cluster + * and overwrite them. + */ + if (lockerTransaction.contains(newEntry)) + lockerTransaction.remove(newEntry); + lockerTransaction.add(newEntry); } /** Public delete method. Uses the put method, with null as the object value. @@ -128,6 +134,7 @@ public class TransactionManager { public void remove(int sysKey, String path, Object locker) throws ClusterStorageException { Integer sysKeyIntObj = new Integer(sysKey); ArrayList lockerTransaction; + Object tempLocker = null; synchronized(locks) { // look to see if this object is already locked if (locks.containsKey(sysKeyIntObj)) { @@ -141,8 +148,9 @@ public class TransactionManager { } else { // either we are the locker, or there is no locker if (locker == null) { // non-locking put/delete - storage.remove(sysKeyIntObj, path); - return; + tempLocker = new Object(); + locks.put(sysKeyIntObj, tempLocker); + lockerTransaction = null; } else {// initialise the transaction locks.put(sysKeyIntObj, locker); @@ -150,17 +158,24 @@ public class TransactionManager { pendingTransactions.put(locker, lockerTransaction); } } - - // create the new entry in the transaction table - TransactionEntry newEntry = new TransactionEntry(sysKeyIntObj, path, null); - /* equals() in TransactionEntry only compares sysKey and path, so we can use - * contains() in ArrayList to looks for preexisting entries for this cluster - * and overwrite them. - */ - if (lockerTransaction.contains(newEntry)) - lockerTransaction.remove(newEntry); - lockerTransaction.add(newEntry); } + + if (tempLocker != null) { + storage.remove(sysKeyIntObj, path); + locks.remove(sysKeyIntObj); + return; + } + + // create the new entry in the transaction table + TransactionEntry newEntry = new TransactionEntry(sysKeyIntObj, path, null); + /* equals() in TransactionEntry only compares sysKey and path, so we can use + * contains() in ArrayList to looks for preexisting entries for this cluster + * and overwrite them. + */ + if (lockerTransaction.contains(newEntry)) + lockerTransaction.remove(newEntry); + lockerTransaction.add(newEntry); + } /** -- cgit v1.2.3