blob: 028f031d8d4b2ca2251c59c813acb93aed2ac72b [file] [log] [blame]
// Copyright 2018 The Bazel Authors. All rights reserved.
//
// 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.devtools.build.lib.worker;
import com.google.devtools.build.lib.actions.UserExecException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Semaphore;
/** A manager to instantiate and distroy multiplexers. */
public class WorkerMultiplexerManager {
/**
* There should only be one WorkerMultiplexer corresponding to workers with the same mnemonic. If
* the WorkerMultiplexer has been constructed, other workers should point to the same one. The
* hash of WorkerKey is used as key.
*/
private static Map<Integer, InstanceInfo> multiplexerInstance;
/** A semaphore to protect multiplexerInstance and multiplexerRefCount objects. */
private static Semaphore semMultiplexer;
static {
multiplexerInstance = new HashMap<>();
semMultiplexer = new Semaphore(1);
}
private WorkerMultiplexerManager() {}
/**
* Returns a WorkerMultiplexer instance to WorkerProxy. WorkerProxies with the same workerHash
* talk to the same WorkerMultiplexer. Also, record how many WorkerProxies are talking to this
* WorkerMultiplexer.
*/
public static WorkerMultiplexer getInstance(Integer workerHash) throws InterruptedException {
semMultiplexer.acquire();
if (!multiplexerInstance.containsKey(workerHash)) {
multiplexerInstance.put(workerHash, new InstanceInfo());
}
multiplexerInstance.get(workerHash).increaseRefCount();
WorkerMultiplexer workerMultiplexer =
multiplexerInstance.get(workerHash).getWorkerMultiplexer();
semMultiplexer.release();
return workerMultiplexer;
}
/** Remove the WorkerMultiplexer instance and reference count since it is no longer in use. */
public static void removeInstance(Integer workerHash)
throws InterruptedException, UserExecException {
semMultiplexer.acquire();
try {
multiplexerInstance.get(workerHash).decreaseRefCount();
if (multiplexerInstance.get(workerHash).getRefCount() == 0) {
multiplexerInstance.get(workerHash).getWorkerMultiplexer().interrupt();
multiplexerInstance.get(workerHash).getWorkerMultiplexer().destroyMultiplexer();
multiplexerInstance.remove(workerHash);
}
} catch (Exception e) {
throw new UserExecException(
ErrorMessage.builder()
.message("NullPointerException while accessing non-existent multiplexer instance.")
.exception(e)
.build()
.toString());
} finally {
semMultiplexer.release();
}
}
public static WorkerMultiplexer getMultiplexer(Integer workerHash) throws UserExecException {
try {
return multiplexerInstance.get(workerHash).getWorkerMultiplexer();
} catch (NullPointerException e) {
throw new UserExecException(
ErrorMessage.builder()
.message("NullPointerException while accessing non-existent multiplexer instance.")
.exception(e)
.build()
.toString());
}
}
public static Integer getRefCount(Integer workerHash) throws UserExecException {
try {
return multiplexerInstance.get(workerHash).getRefCount();
} catch (NullPointerException e) {
throw new UserExecException(
ErrorMessage.builder()
.message("NullPointerException while accessing non-existent multiplexer instance.")
.exception(e)
.build()
.toString());
}
}
public static Integer getInstanceCount() {
return multiplexerInstance.keySet().size();
}
/** Contains the WorkerMultiplexer instance and reference count */
static class InstanceInfo {
private WorkerMultiplexer workerMultiplexer;
private Integer refCount;
public InstanceInfo() {
this.workerMultiplexer = new WorkerMultiplexer();
this.refCount = 0;
}
public void increaseRefCount() {
refCount = refCount + 1;
}
public void decreaseRefCount() {
refCount = refCount - 1;
}
public WorkerMultiplexer getWorkerMultiplexer() {
return workerMultiplexer;
}
public Integer getRefCount() {
return refCount;
}
}
}