1 19 package org.netbeans.mdr.util; 20 21 import java.util.HashMap ; 22 import java.util.HashSet ; 23 import org.netbeans.api.mdr.events.TransactionEvent; 24 import org.netbeans.mdr.NBMDRepositoryImpl; 25 import org.netbeans.mdr.storagemodel.MdrStorage; 26 import org.netbeans.mdr.persistence.StorageException; 27 28 34 public class MultipleReadersMutex extends TransactionMutex { 35 36 37 38 39 40 41 private Thread writer = null; 42 43 44 private volatile int counter = 0; 45 46 53 private final HashMap readers = new HashMap (10); 54 55 private final HashSet mutators = new HashSet (2); 56 57 58 private volatile boolean fail = false; 59 60 61 62 63 64 65 public MultipleReadersMutex(Object p1, Object p2, Object p3) { 66 super(p1, p2, p3); 67 } 68 69 70 71 72 73 public boolean willFail() { 74 return fail; 75 } 76 77 80 public boolean pendingChanges() { 81 return counter > 0; 82 } 83 84 85 86 87 88 98 public void enter(boolean writeAccess) { 99 Thread thread = Thread.currentThread(); 101 boolean isMutator; 102 synchronized (this) { 103 Counter rCount = (Counter) readers.get(thread); 104 isMutator = mutators.contains(thread); 105 while ((counter > 0 && writer != thread) || 106 (writeAccess && (!mutators.containsAll(readers.keySet())))) { 107 110 if ((rCount != null) && !isMutator) { 114 System.err.println("Writable lock nested in read-only lock."); 115 Thread.dumpStack(); 116 throw new DebugException("Writable lock nested in read-only lock."); 117 } 118 try { 119 this.wait(); 120 } catch (InterruptedException e) { 121 Logger.getDefault().notify(Logger.INFORMATIONAL, e); 122 } 123 } 124 if (writeAccess || counter > 0) { 125 if (counter == 0) { 126 writer = thread; 127 if (isMutator) { 128 counter = rCount.intValue(); 129 } 130 readers.remove(thread); 131 mutators.remove(thread); 132 } 133 counter++; 134 } else { 135 if (rCount == null) { 136 readers.put(thread, new Counter()); 137 } else { 138 rCount.inc(); 139 } 140 } 141 } 142 143 if (writeAccess && (counter == 1 || isMutator)) { 144 start(); 145 } 146 } 147 148 public synchronized void mutateToWrite() { 149 Thread thread = Thread.currentThread(); 150 if (writer != thread) { 151 if (readers.get(thread) == null) { 152 throw new DebugException("Cannot mutate transaction - no transaction opened."); 153 } 154 mutators.add(Thread.currentThread()); 155 } 156 enter(true); 157 } 158 159 171 public boolean leave(boolean fail) { 172 boolean result = false; 174 try { 175 this.fail |= fail; 176 if (counter == 1) { 177 result = true; 179 end(this.fail); 180 } 181 } finally { 182 synchronized (this) { 183 if (counter > 0) { 184 if ((--counter) == 0) { 185 writer = null; 186 this.fail = false; 187 this.notifyAll(); 188 } 189 } else { 190 Thread thread = Thread.currentThread(); 191 Counter rCount = (Counter) readers.get(thread); 192 if (rCount == null) { 193 throw new DebugException("Error: leave() without enter()."); 194 } else { 195 if (rCount.dec() == 0) { 196 try { 197 result = true; 198 readers.remove(thread); 199 } finally { 200 this.notifyAll(); 201 } 202 } 203 } 204 if (fail) throw new DebugException("Cannot fail when in read mode."); 205 } 206 } 207 } 208 return result; 209 } 210 211 212 213 214 215 219 private static class Counter { 220 private int value = 1; 221 222 225 public Counter() { 226 } 227 228 231 public int intValue() { 232 return value; 233 } 234 235 242 public int dec() { 243 if (value <= 0) throw new DebugException("Couter underflow: " + value); 244 return (--value); 245 } 246 247 252 public int inc() { 253 return (++value); 254 } 255 } 256 } 257 | Popular Tags |