org.apache.flink.runtime.state.gemini.engine.rm.GarbageReleaseManagerImpl Maven / Gradle / Ivy
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 org.apache.flink.runtime.state.gemini.engine.rm;
import org.apache.flink.runtime.state.gemini.engine.dbms.GContext;
import org.apache.flink.shaded.guava18.com.google.common.collect.Queues;
import org.apache.flink.shaded.guava18.com.google.common.util.concurrent.ThreadFactoryBuilder;
import java.util.Queue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* A Garbage Release Manager default implement.
*/
public class GarbageReleaseManagerImpl implements GarbageReleaseManager {
private static final int LOOP_INTERVAL = 10;
private static final int LOOP_INTERVAL_WHEN_EMPTY = 100;
private final GContext gContext;
private boolean threadStarted = false;
private ExecutorService executor;
// guava implement of ConcurrentLinkedQueue is more efficent.
private Queue monitorQueue = Queues.newConcurrentLinkedQueue();
public GarbageReleaseManagerImpl(GContext gContext) {
this.gContext = gContext;
}
/**
* Register a {@link T} to let Garbage Release Manager to monitor or handle release.
* @param object the {@link T}.
*/
public void enqueue(T object) {
if (object.isFreed()) {
return;
}
if (object.refCnt() == 0 && object.canSyncFree()) {
object.doFree();
return;
}
object.setSeqID(gContext.getAccessNumber());
monitorQueue.add(object);
}
public void start() {
if (threadStarted) {
return;
}
ThreadFactory namedThreadFactory = new ThreadFactoryBuilder().setNameFormat(gContext.getGConfiguration().getExecutorPrefixName() + "GeminiReleaseManager-%d").build();
this.executor = new ThreadPoolExecutor(1,
1,
0L,
TimeUnit.MILLISECONDS,
new LinkedBlockingQueue(Short.MAX_VALUE),
namedThreadFactory);
threadStarted = true;
executor.submit(this);
}
@Override
public void run() {
while (threadStarted) {
int size = monitorQueue.size();
while (size-- > 0) {
T object = monitorQueue.poll();
if (object != null) {
if (object.isFreed()) {
continue;
}
if (object.refCnt() <= 0 && (object.getSeqID() != gContext.getAccessNumber())) {
object.doFree();
} else {
monitorQueue.add(object);
}
}
}
try {
if (monitorQueue.size() > 0) {
Thread.sleep(LOOP_INTERVAL);
} else {
Thread.sleep(LOOP_INTERVAL_WHEN_EMPTY);
}
} catch (InterruptedException ignore) {
}
}
}
@Override
public void close() {
if (threadStarted) {
threadStarted = false;
executor.shutdownNow();
try {
executor.awaitTermination(1000, TimeUnit.SECONDS);
} catch (InterruptedException ingore) {
}
}
// Do last round cleaning up.
while (monitorQueue.size() > 0) {
T object = monitorQueue.poll();
if (object != null) {
if (object.isFreed()) {
continue;
}
if (object.refCnt() <= 0) {
object.doFree();
}
}
}
}
}