/** * Attempts to schedule an asynchronous task to apply the pending operations to the page * replacement policy. If the executor rejects the task then it is run directly. */ void scheduleDrainBuffers() { if (drainStatus() >= PROCESSING_TO_IDLE) { return; } if (evictionLock.tryLock()) { try { int drainStatus = drainStatus(); if (drainStatus >= PROCESSING_TO_IDLE) { return; } lazySetDrainStatus(PROCESSING_TO_IDLE); executor().execute(drainBuffersTask); } catch (Throwable t) { logger.log(Level.WARNING, "Exception thrown when submitting maintenance task", t); maintenance(/* ignored */ null); } finally { evictionLock.unlock(); } } }
/** * Performs the maintenance work, blocking until the lock is acquired. Any exception thrown, such * as by {@link CacheWriter#delete}, is propagated to the caller. * * @param task an additional pending task to run, or {@code null} if not present */ void performCleanUp(@Nullable Runnable task) { evictionLock.lock(); try { maintenance(task); } finally { evictionLock.unlock(); } if ((drainStatus() == REQUIRED) && (executor == ForkJoinPool.commonPool())) { scheduleDrainBuffers(); } }
/** * Conditionally schedules the asynchronous maintenance task after a write operation. If the * task status was IDLE or REQUIRED then the maintenance task is scheduled immediately. If it * is already processing then it is set to transition to REQUIRED upon completion so that a new * execution is triggered by the next operation. */ void scheduleAfterWrite() { for (;;) { switch (drainStatus()) { case IDLE: casDrainStatus(IDLE, REQUIRED); scheduleDrainBuffers(); return; case REQUIRED: scheduleDrainBuffers(); return; case PROCESSING_TO_IDLE: if (casDrainStatus(PROCESSING_TO_IDLE, PROCESSING_TO_REQUIRED)) { return; } continue; case PROCESSING_TO_REQUIRED: return; default: throw new IllegalStateException(); } } }
private void status() { int drainStatus; int pendingWrites; local.evictionLock.lock(); try { pendingWrites = local.writeBuffer().size(); drainStatus = local.drainStatus(); } finally { local.evictionLock.unlock(); } LocalTime elapsedTime = LocalTime.ofSecondOfDay(stopwatch.elapsed(TimeUnit.SECONDS)); System.out.printf("---------- %s ----------%n", elapsedTime); System.out.printf("Pending reads: %,d; writes: %,d%n", local.readBuffer.size(), pendingWrites); System.out.printf("Drain status = %s (%s)%n", STATUS[drainStatus], drainStatus); System.out.printf("Evictions = %,d%n", cache.stats().evictionCount()); System.out.printf("Size = %,d (max: %,d)%n", local.data.mappingCount(), operation.maxEntries); System.out.printf("Lock = [%s%n", StringUtils.substringAfter( local.evictionLock.toString(), "[")); System.out.printf("Pending tasks = %,d%n", ForkJoinPool.commonPool().getQueuedSubmissionCount()); long maxMemory = Runtime.getRuntime().maxMemory(); long freeMemory = Runtime.getRuntime().freeMemory(); long allocatedMemory = Runtime.getRuntime().totalMemory(); System.out.printf("Max Memory = %,d bytes%n", maxMemory); System.out.printf("Free Memory = %,d bytes%n", freeMemory); System.out.printf("Allocated Memory = %,d bytes%n", allocatedMemory); System.out.println(); }
/** * Performs the pending maintenance work and sets the state flags during processing to avoid * excess scheduling attempts. The read buffer, write buffer, and reference queues are * drained, followed by expiration, and size-based eviction. * * @param task an additional pending task to run, or {@code null} if not present */ @GuardedBy("evictionLock") void maintenance(@Nullable Runnable task) { lazySetDrainStatus(PROCESSING_TO_IDLE); try { drainReadBuffer(); drainWriteBuffer(); if (task != null) { task.run(); } drainKeyReferences(); drainValueReferences(); expireEntries(); evictEntries(); } finally { if ((drainStatus() != PROCESSING_TO_IDLE) || !casDrainStatus(PROCESSING_TO_IDLE, IDLE)) { lazySetDrainStatus(REQUIRED); } } }
/** * Attempts to schedule an asynchronous task to apply the pending operations to the page * replacement policy. If the executor rejects the task then it is run directly. */ void scheduleDrainBuffers() { if (drainStatus() >= PROCESSING_TO_IDLE) { return; } if (evictionLock.tryLock()) { try { int drainStatus = drainStatus(); if (drainStatus >= PROCESSING_TO_IDLE) { return; } lazySetDrainStatus(PROCESSING_TO_IDLE); executor().execute(drainBuffersTask); } catch (Throwable t) { logger.log(Level.WARNING, "Exception thrown when submitting maintenance task", t); maintenance(/* ignored */ null); } finally { evictionLock.unlock(); } } }
/** * Conditionally schedules the asynchronous maintenance task after a write operation. If the * task status was IDLE or REQUIRED then the maintenance task is scheduled immediately. If it * is already processing then it is set to transition to REQUIRED upon completion so that a new * execution is triggered by the next operation. */ void scheduleAfterWrite() { for (;;) { switch (drainStatus()) { case IDLE: casDrainStatus(IDLE, REQUIRED); scheduleDrainBuffers(); return; case REQUIRED: scheduleDrainBuffers(); return; case PROCESSING_TO_IDLE: if (casDrainStatus(PROCESSING_TO_IDLE, PROCESSING_TO_REQUIRED)) { return; } continue; case PROCESSING_TO_REQUIRED: return; default: throw new IllegalStateException(); } } }
/** * Performs the pending maintenance work and sets the state flags during processing to avoid * excess scheduling attempts. The read buffer, write buffer, and reference queues are * drained, followed by expiration, and size-based eviction. * * @param task an additional pending task to run, or {@code null} if not present */ @GuardedBy("evictionLock") void maintenance(@Nullable Runnable task) { lazySetDrainStatus(PROCESSING_TO_IDLE); try { drainReadBuffer(); drainWriteBuffer(); if (task != null) { task.run(); } drainKeyReferences(); drainValueReferences(); expireEntries(); evictEntries(); } finally { if ((drainStatus() != PROCESSING_TO_IDLE) || !casDrainStatus(PROCESSING_TO_IDLE, IDLE)) { lazySetDrainStatus(REQUIRED); } } }