AutoScaleProcessor(AutoScalerConfig configuration, ScheduledExecutorService maintenanceExecutor) { this.configuration = configuration; this.maintenanceExecutor = maintenanceExecutor; serializer = new JavaSerializer<>(); writerConfig = EventWriterConfig.builder().build(); writer = new AtomicReference<>(); cache = CacheBuilder.newBuilder() .initialCapacity(INITIAL_CAPACITY) .maximumSize(MAX_CACHE_SIZE) .expireAfterAccess(configuration.getCacheExpiry().getSeconds(), TimeUnit.SECONDS) .removalListener(RemovalListeners.asynchronous((RemovalListener<String, Pair<Long, Long>>) notification -> { if (notification.getCause().equals(RemovalCause.EXPIRED)) { triggerScaleDown(notification.getKey(), true); } }, maintenanceExecutor)) .build(); CompletableFuture.runAsync(this::bootstrapRequestWriters, maintenanceExecutor); }
@Inject public AssetDownloadCountStoreImpl(@Named(ComponentDatabase.NAME) final Provider<DatabaseInstance> databaseInstance, @Named("${nexus.assetdownloads.enabled:-true}") final boolean enabled, @Named("${nexus.assetdownloads.cache.size:-10000}") final int cacheSize, @Named("${nexus.assetdownloads.cache.duration:-3600}") final int cacheDuration, final AssetDownloadCountEntityAdapter entityAdapter, final AssetDownloadHistoricDataCleaner historicDataCleaner, final CacheRemovalListener cacheRemovalListener) { this.databaseInstance = checkNotNull(databaseInstance); this.entityAdapter = checkNotNull(entityAdapter); this.historicDataCleaner = checkNotNull(historicDataCleaner); this.enabled = enabled; cache = CacheBuilder.newBuilder() .maximumSize(cacheSize) .expireAfterWrite(cacheDuration, TimeUnit.SECONDS) .removalListener(RemovalListeners.asynchronous(cacheRemovalListener, NexusExecutorService .forCurrentSubject(Executors.newSingleThreadExecutor( new NexusThreadFactory("assetdownloads-count", "Asset Downloads Count"))))) .build(new CacheLoader<CacheEntryKey, AtomicLong>() { @Override public AtomicLong load(final CacheEntryKey cacheEntryKey) throws Exception { return new AtomicLong(0); } }); }
/** * Creates a new cache. * This method is private because external access should be made through * {@link #getSharedCache(long, CanvasDataLoader)}. * * @param kilobyteCapacity capacity of the cache. * @param canvasDataLoader loader implementation for the cache. * @param recordStats indicates whether the cache should record statistics. * * @throws IllegalStateException * if any errors occur. */ private CanvasDataCache(final long kilobyteCapacity, final CanvasDataLoader canvasDataLoader, final boolean recordStats) throws IllegalArgumentException, IllegalStateException { if (kilobyteCapacity < 1) { this.kilobyteCapacity = 1; } else { this.kilobyteCapacity = kilobyteCapacity; } this.weigher = new Weigher<CanvasId, CachedCanvasData>() { @Override public int weigh(@Nullable final CanvasId key, @Nonnull final CachedCanvasData value) { long kiloBytes = value.getKilobytes(); // hopefully we'll never have > 2000 gigabyte file, // but if so it simply won't be fairly weighted if (kiloBytes > Integer.MAX_VALUE) { LOG.warn("weightOf: truncating weight for " + kiloBytes + " Kb item " + value); kiloBytes = Integer.MAX_VALUE; } else if (kiloBytes == 0) { // zero weights are not supported, so we need to set empty file weight to 1 kiloBytes = 1; } return (int) kiloBytes; } }; // separate thread pool for removing data that expires from the cache final ExecutorService removalService = Executors.newFixedThreadPool(4); final RemovalListener<CanvasId, CachedCanvasData> removalListener = removal -> { final CachedCanvasData cachedCanvasData = removal.getValue(); if (cachedCanvasData != null) { cachedCanvasData.remove(); } }; this.asyncRemovalListener = RemovalListeners.asynchronous(removalListener, removalService); this.canvasDataLoader = canvasDataLoader; this.buildCache(recordStats); LOG.info("<init>: exit"); }