// Copyright (C) 2012 The Android Open Source Project // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package com.google.gerrit.server.plugins; import com.google.gerrit.server.git.WorkQueue; import com.google.gerrit.server.util.TimeUtil; import com.google.inject.Inject; import com.google.inject.Singleton; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; @Singleton class PluginCleanerTask implements Runnable { private final WorkQueue workQueue; private final PluginLoader loader; private volatile int pending; private Future<?> self; private int attempts; private long start; @Inject PluginCleanerTask(WorkQueue workQueue, PluginLoader loader) { this.workQueue = workQueue; this.loader = loader; } @Override public void run() { try { for (int t = 0; t < 2 * (attempts + 1); t++) { System.gc(); Thread.sleep(50); } } catch (InterruptedException e) { } int left = loader.processPendingCleanups(); synchronized (this) { pending = left; self = null; if (0 < left) { long waiting = TimeUtil.nowMs() - start; PluginLoader.log.warn(String.format( "%d plugins still waiting to be reclaimed after %d minutes", pending, TimeUnit.MILLISECONDS.toMinutes(waiting))); attempts = Math.min(attempts + 1, 15); ensureScheduled(); } else { attempts = 0; } } } @Override public String toString() { int p = pending; if (0 < p) { return String.format("Plugin Cleaner (waiting for %d plugins)", p); } return "Plugin Cleaner"; } synchronized void clean(int expect) { if (self == null && pending == 0) { start = TimeUtil.nowMs(); } pending = expect; ensureScheduled(); } private void ensureScheduled() { if (self == null && 0 < pending) { if (attempts == 1) { self = workQueue.getDefaultQueue().schedule( this, 30, TimeUnit.SECONDS); } else { self = workQueue.getDefaultQueue().schedule( this, attempts + 1, TimeUnit.MINUTES); } } } }