1 package org.jboss.cache.interceptors; 2 3 import org.jboss.cache.CacheException; 4 import org.jboss.cache.CacheImpl; 5 import org.jboss.cache.CacheSPI; 6 import org.jboss.cache.Fqn; 7 import org.jboss.cache.GlobalTransaction; 8 import org.jboss.cache.NodeSPI; 9 import org.jboss.cache.marshall.MethodCall; 10 import org.jboss.cache.marshall.MethodCallFactory; 11 import org.jboss.cache.marshall.MethodDeclarations; 12 13 import java.util.ArrayList ; 14 import java.util.Iterator ; 15 import java.util.concurrent.locks.ReentrantLock ; 16 17 25 public class CreateIfNotExistsInterceptor extends Interceptor 26 { 27 28 private final ReentrantLock put_lock = new ReentrantLock (); 29 30 private final ReentrantLock remove_lock = new ReentrantLock (); 31 32 private final ArrayList put_list = new ArrayList (); 33 34 private final ArrayList remove_list = new ArrayList (); 35 36 37 public void setCache(CacheSPI cache) 38 { 39 super.setCache(cache); 40 } 41 42 61 62 105 106 113 public Object invoke(MethodCall m) throws Throwable 114 { 115 Fqn fqn; 116 boolean isPut = MethodDeclarations.isPutMethod(m.getMethodId()), 117 isRemove = m.getMethodId() == MethodDeclarations.removeNodeMethodLocal_id, 118 isEvict = m.getMethodId() == MethodDeclarations.evictNodeMethodLocal_id; 119 120 if (isPut || isRemove || isEvict) 121 { Object [] args = m.getArgs(); 123 fqn = (Fqn) (args != null ? (isEvict ? args[0] : args[1]) : null); 124 if (fqn == null) 125 { 126 throw new CacheException("failed extracting FQN from method " + m); 127 } 128 129 if (isPut) 130 { try 132 { 133 addFqnToPutList(fqn, put_lock); 134 findAndBlockOnRemove(fqn, remove_lock); 135 if (!cache.getRoot().hasChild(fqn)) 136 { 137 GlobalTransaction gtx = cache.getInvocationContext().getGlobalTransaction(); 138 if (log.isTraceEnabled()) 139 { 140 log.trace("creating node " + fqn); 141 } 142 createNode(fqn, gtx); 143 } 144 145 return super.invoke(m); 146 } 147 finally 148 { 149 removeFqnFromPutList(fqn, put_lock); 150 } 151 } 152 else 153 { try 155 { 156 findAndBlockOnPut(fqn, put_lock); addFqnToRemoveList(fqn, remove_lock); 158 put_lock.unlock(); 159 return super.invoke(m); 161 } 162 finally 163 { 164 if (put_lock.isHeldByCurrentThread()) 165 { 166 put_lock.unlock(); 167 } 168 removeFqnFromRemoveList(fqn, remove_lock); 169 } 170 } 171 } 172 return super.invoke(m); 173 } 174 175 176 185 private void findAndBlockOnPut(Fqn fqn, ReentrantLock lock) throws InterruptedException 186 { 187 Fqn tmp; 188 while (true) 189 { 190 lock.lockInterruptibly(); 192 tmp = findFqnInPutList(fqn); 193 if (tmp == null) { 195 return; 196 } 197 if (log.isTraceEnabled()) 198 { 199 log.trace("found " + tmp + " in put-list, waiting"); 200 } 201 synchronized (tmp) 202 { 203 lock.unlock(); 204 tmp.wait(); 205 } 206 if (log.isTraceEnabled()) 207 { 208 log.trace("wait() for put-list on " + tmp + " got notified"); 209 } 210 } 216 } 217 218 226 private void findAndBlockOnRemove(Fqn fqn, ReentrantLock lock) throws InterruptedException 227 { 228 Fqn tmp; 229 while (true) 230 { 231 lock.lockInterruptibly(); 232 try 233 { 234 tmp = findFqnInRemoveList(fqn); 235 if (tmp == null) { 237 return; 238 } 239 if (log.isTraceEnabled()) 240 { 241 log.trace("found " + tmp + " in remove-list, waiting"); 242 } 243 synchronized (tmp) 244 { 245 lock.unlock(); 246 tmp.wait(); 247 } 248 if (log.isTraceEnabled()) 249 { 250 log.trace("wait() for remove-list on " + tmp + " got notified"); 251 } 252 } 253 finally 254 { 255 lock.unlock(); 256 } 257 } 258 } 259 260 261 private Fqn findFqnInPutList(Fqn fqn) 262 { 263 Fqn tmp; 264 for (Iterator it = put_list.iterator(); it.hasNext();) 265 { 266 tmp = (Fqn) it.next(); 267 if (tmp.isChildOf(fqn) || tmp.equals(fqn)) { 269 return tmp; 270 } 271 } 272 return null; 273 } 274 275 private Fqn findFqnInRemoveList(Fqn fqn) 276 { 277 Fqn tmp; 278 for (Iterator it = remove_list.iterator(); it.hasNext();) 279 { 280 tmp = (Fqn) it.next(); 281 if (fqn.isChildOf(tmp) || fqn.equals(tmp)) { 283 return tmp; 284 } 285 } 286 return null; 287 } 288 289 private void addFqnToPutList(Fqn fqn, ReentrantLock lock) 290 throws InterruptedException 291 { 292 lock.lockInterruptibly(); 293 try 294 { 295 if (!put_list.contains(fqn)) 296 { 297 put_list.add(fqn); 298 if (log.isTraceEnabled()) 299 { 300 log.trace("adding " + fqn + " to put-list (size=" + put_list.size() + ")"); 301 } 302 } 303 } 304 finally 305 { 306 lock.unlock(); 307 } 308 } 309 310 private void addFqnToRemoveList(Fqn fqn, ReentrantLock lock) 311 throws InterruptedException 312 { 313 lock.lockInterruptibly(); 314 try 315 { 316 if (!remove_list.contains(fqn)) 317 { 318 remove_list.add(fqn); 319 if (log.isTraceEnabled()) 320 { 321 log.trace("adding " + fqn + " to remove-list (size=" + remove_list.size() + ")"); 322 } 323 } 324 } 325 finally 326 { 327 lock.unlock(); 328 } 329 } 330 331 332 private void removeFqnFromPutList(Fqn fqn, ReentrantLock lock) 333 throws InterruptedException 334 { 335 lock.lockInterruptibly(); 336 try 337 { 338 if (log.isTraceEnabled()) 339 { 340 log.trace("removing " + fqn + " from put-list (size=" + put_list.size() + ")"); 341 } 342 put_list.remove(fqn); 343 lock.unlock(); 344 synchronized (fqn) 345 { 346 fqn.notifyAll(); 347 } 348 } 349 finally 350 { 351 lock.unlock(); 352 } 353 } 354 355 private void removeFqnFromRemoveList(Fqn fqn, ReentrantLock lock) 356 throws InterruptedException 357 { 358 lock.lockInterruptibly(); 359 try 360 { 361 if (log.isTraceEnabled()) 362 { 363 log.trace("removing " + fqn + " from remove-list (size=" + remove_list.size() + ")"); 364 } 365 remove_list.remove(fqn); 366 lock.unlock(); 367 synchronized (fqn) 368 { 369 fqn.notifyAll(); 370 } 371 } 372 finally 373 { 374 lock.unlock(); 375 } 376 } 377 378 private void createNode(Fqn fqn, GlobalTransaction tx) 379 { 380 NodeSPI n, child_node; 381 Object child_name; 382 Fqn tmp_fqn = Fqn.ROOT; 383 384 if (fqn == null) return; 385 synchronized (this) 386 { 387 int treeNodeSize = fqn.size(); 388 n = cache.getRoot(); 389 for (int i = 0; i < treeNodeSize; i++) 390 { 391 child_name = fqn.get(i); 392 tmp_fqn = new Fqn(tmp_fqn, child_name); 393 child_node = n.getChildDirect(child_name); 394 if (child_node == null) 395 { 396 child_node = n.addChildDirect(new Fqn(child_name)); 398 if (tx != null) 399 { 400 MethodCall undo_op = MethodCallFactory.create(MethodDeclarations.removeNodeMethodLocal, 401 tx, tmp_fqn, false); 402 ((CacheImpl) cache).addUndoOperation(tx, undo_op); 403 404 } 408 cache.getNotifier().notifyNodeCreated(tmp_fqn, true, true); 409 cache.getNotifier().notifyNodeCreated(tmp_fqn, false, true); 410 } 411 n = child_node; 412 } 413 } 414 } 415 416 } 417 | Popular Tags |