@Override @SuppressWarnings({"unchecked"}) public int getOrCreate(long o) { if (DependencyTracker.isBypassCaches()) { return calculatable.calculate(owner, o); } else { preCheckDirty(); lock(o); try { Object v = load(o); ExceptionHelper.throwIfExceptionRecordNotExpired(v); if (v != UNDEFINED) { DependencyTracker.mark(getDependencyNode()); hit(); return (Integer) v; } DependencyNode callerNode = DependencyTracker.track(getDependencyNode()); try { while (true) { try { return create(o); } catch (ResourceOccupied e) { if (callerNode != null) { throw e; } else { unlock(o); try { e.getResource().waitForEndOfModification(); } finally { lock(o); } v = load(o); ExceptionHelper.throwIfExceptionRecordNotExpired(v); if (v != UNDEFINED) { hit(); return (Integer) v; } } } } } finally { DependencyTracker.exit(callerNode); } } finally { unlock(o); postCheckDirty(); } } }
@SuppressWarnings({"unchecked"}) protected int create(long o) { long start = System.nanoTime(); try { int retry = 0; // retry on exception loop while (true) { try { int t = calculatable.calculate(owner, o); // successful invocation => just store the value and return save(o, t); return t; } catch (Exception e) { // We catch Exception here, but not Error and not Throwable. // this is because in case of Error we are likely have no chance even to save // an ExceptionRecord to a storage, so don't even try to do so. // For example in case of OOM (out of memory) it may be impossible to create // even a single new object. CacheExceptionHandler exceptionHandler = getDescriptor().getExceptionHandler(); switch (exceptionHandler.getAction(retry, e)) { case RETRY: retry++; continue; case REMEMBER_AND_RETHROW: save( o, new ExceptionRecord( e, exceptionHandler.getRememberExceptionExpirationTimestamp(e))); // fall through case RETHROW: default: // this method always throws an exception ExceptionHelper.throwCheckedExceptionHack(e); break; } } } } finally { // record calculation time even if calculation fails long end = System.nanoTime(); miss(end - start); } }