/*
* The Alluxio Open Foundation licenses this work under the Apache License, version 2.0
* (the "License"). You may not use this work except in compliance with the License, which is
* available at www.apache.org/licenses/LICENSE-2.0
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied, as more fully set forth in the License.
*
* See the NOTICE file distributed with this work for information regarding copyright ownership.
*/
package alluxio.worker.file;
import alluxio.Configuration;
import alluxio.Constants;
import alluxio.PropertyKey;
import alluxio.Server;
import alluxio.heartbeat.HeartbeatContext;
import alluxio.heartbeat.HeartbeatThread;
import alluxio.thrift.FileSystemWorkerClientService;
import alluxio.underfs.UfsManager;
import alluxio.util.CommonUtils;
import alluxio.util.ThreadFactoryUtils;
import alluxio.util.network.NetworkAddressUtils;
import alluxio.util.network.NetworkAddressUtils.ServiceType;
import alluxio.wire.WorkerNetAddress;
import alluxio.worker.AbstractWorker;
import alluxio.worker.block.BlockWorker;
import com.google.common.base.Function;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableSet;
import com.google.common.util.concurrent.RateLimiter;
import org.apache.thrift.TProcessor;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import javax.annotation.concurrent.NotThreadSafe;
/**
* This class is responsible for persisting files when requested by the master and a defunct
* {@link FileSystemWorkerClientServiceHandler} which always returns UnsupportedOperation Exception.
*/
@NotThreadSafe // TODO(jiri): make thread-safe (c.f. ALLUXIO-1624)
public final class DefaultFileSystemWorker extends AbstractWorker implements FileSystemWorker {
private static final Set<Class<? extends Server>> DEPS =
ImmutableSet.<Class<? extends Server>>of(BlockWorker.class);
/** Logic for managing file persistence. */
private final FileDataManager mFileDataManager;
/** Client for file system master communication. */
private final FileSystemMasterClient mFileSystemMasterWorkerClient;
/** Logic for handling RPC requests. */
private final FileSystemWorkerClientServiceHandler mServiceHandler;
/** This worker's worker ID. May be updated by another thread if worker re-registration occurs. */
private final AtomicReference<Long> mWorkerId;
/** The service that persists files. */
private Future<?> mFilePersistenceService;
/** Handler to the ufs manager. */
private final UfsManager mUfsManager;
/**
* Creates a new DefaultFileSystemWorker.
*
* @param blockWorker the block worker handle
* @param ufsManager the ufs manager
*/
DefaultFileSystemWorker(BlockWorker blockWorker, UfsManager ufsManager) {
super(Executors.newFixedThreadPool(3,
ThreadFactoryUtils.build("file-system-worker-heartbeat-%d", true)));
mWorkerId = blockWorker.getWorkerId();
mUfsManager = ufsManager;
mFileDataManager = new FileDataManager(Preconditions.checkNotNull(blockWorker),
RateLimiter.create(Configuration.getBytes(PropertyKey.WORKER_FILE_PERSIST_RATE_LIMIT)),
mUfsManager);
// Setup AbstractMasterClient
mFileSystemMasterWorkerClient = new FileSystemMasterClient(
NetworkAddressUtils.getConnectAddress(ServiceType.MASTER_RPC));
mServiceHandler = new FileSystemWorkerClientServiceHandler();
}
@Override
public Set<Class<? extends Server>> getDependencies() {
return DEPS;
}
@Override
public String getName() {
return Constants.FILE_SYSTEM_WORKER_NAME;
}
@Override
public Map<String, TProcessor> getServices() {
Map<String, TProcessor> services = new HashMap<>();
services.put(Constants.FILE_SYSTEM_WORKER_CLIENT_SERVICE_NAME,
new FileSystemWorkerClientService.Processor<>(mServiceHandler));
return services;
}
@Override
public void start(WorkerNetAddress address) {
mFilePersistenceService = getExecutorService().submit(
new HeartbeatThread(HeartbeatContext.WORKER_FILESYSTEM_MASTER_SYNC,
new FileWorkerMasterSyncExecutor(mFileDataManager, mFileSystemMasterWorkerClient,
mWorkerId),
Configuration.getInt(PropertyKey.WORKER_FILESYSTEM_HEARTBEAT_INTERVAL_MS)));
}
@Override
public void stop() {
if (mFilePersistenceService != null) {
mFilePersistenceService.cancel(true);
}
// The executor shutdown needs to be done in a loop with retry because the interrupt
// signal can sometimes be ignored.
CommonUtils.waitFor("file system worker executor shutdown", new Function<Void, Boolean>() {
@Override
public Boolean apply(Void input) {
getExecutorService().shutdownNow();
try {
return getExecutorService().awaitTermination(100, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
});
mFileSystemMasterWorkerClient.close();
}
}