All Downloads are FREE. Search and download functionalities are using the official Maven repository.

alluxio.client.block.BlockStoreContext Maven / Gradle / Ivy

There is a newer version: 1.4.0
Show newest version
/*
 * 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.client.block;

import alluxio.Constants;
import alluxio.client.ClientContext;
import alluxio.exception.ExceptionMessage;
import alluxio.exception.PreconditionMessage;
import alluxio.resource.CloseableResource;
import alluxio.util.IdUtils;
import alluxio.util.network.NetworkAddressUtils;
import alluxio.wire.WorkerInfo;
import alluxio.wire.WorkerNetAddress;
import alluxio.worker.ClientMetrics;

import com.google.common.base.Preconditions;
import com.google.common.base.Throwables;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import javax.annotation.concurrent.ThreadSafe;

/**
 * A shared context in each client JVM for common block master client functionality such as a pool
 * of master clients and a pool of local worker clients. Any remote clients will be created and
 * destroyed on a per use basis.
 * 

* NOTE: The context maintains a pool of block master clients and a pool of block worker clients * that are already thread-safe. Synchronizing {@link BlockStoreContext} methods could lead to * deadlock: thread A attempts to acquire a client when there are no clients left in the pool and * blocks holding a lock on the {@link BlockStoreContext}, when thread B attempts to release a * client it owns, it is unable to do so, because thread A holds the lock on * {@link BlockStoreContext}. */ @ThreadSafe public enum BlockStoreContext { INSTANCE; private static final Logger LOG = LoggerFactory.getLogger(Constants.LOGGER_TYPE); private BlockMasterClientPool mBlockMasterClientPool; /** * A map from the worker's address to its client pool. Guarded by * {@link #initializeLocalBlockWorkerClientPool()} for client acquisition. There is no guard for * releasing client, and client can be released anytime. */ private final Map mLocalBlockWorkerClientPoolMap = new ConcurrentHashMap<>(); private boolean mLocalBlockWorkerClientPoolInitialized = false; /** * Creates a new block store context. */ BlockStoreContext() { reset(); } /** * Initializes {@link #mLocalBlockWorkerClientPoolMap}. This method is supposed be called in a * lazy manner. */ private synchronized void initializeLocalBlockWorkerClientPool() { if (!mLocalBlockWorkerClientPoolInitialized) { for (WorkerNetAddress localWorkerAddress : getWorkerAddresses( NetworkAddressUtils.getLocalHostName(ClientContext.getConf()))) { mLocalBlockWorkerClientPoolMap.put(localWorkerAddress, new BlockWorkerClientPool(localWorkerAddress)); } mLocalBlockWorkerClientPoolInitialized = true; } } /** * Gets the worker addresses with the given hostname by querying the master. Returns all the * addresses, if the hostname is an empty string. * * @param hostname hostname of the worker to query, empty string denotes any worker * @return a list of {@link WorkerNetAddress} with the given hostname */ private List getWorkerAddresses(String hostname) { List addresses = new ArrayList<>(); try (CloseableResource masterClient = acquireMasterClientResource()) { List workers = masterClient.get().getWorkerInfoList(); for (WorkerInfo worker : workers) { if (hostname.isEmpty() || worker.getAddress().getHost().equals(hostname)) { addresses.add(worker.getAddress()); } } } catch (Exception e) { Throwables.propagate(e); } return addresses; } /** * Acquires a block master client resource from the block master client pool. The resource is * {@code Closeable}. * * @return the acquired block master client resource */ public CloseableResource acquireMasterClientResource() { return new CloseableResource(mBlockMasterClientPool.acquire()) { @Override public void close() { mBlockMasterClientPool.release(get()); } }; } /** * Obtains a client for a worker with the given address. * * @param address the address of the worker to get a client to * @return a {@link BlockWorkerClient} connected to the worker with the given hostname * @throws IOException if no Alluxio worker is available for the given hostname */ public BlockWorkerClient acquireWorkerClient(WorkerNetAddress address) throws IOException { BlockWorkerClient client; if (address == null) { throw new RuntimeException(ExceptionMessage.NO_WORKER_AVAILABLE.getMessage()); } if (address.getHost().equals(NetworkAddressUtils.getLocalHostName(ClientContext.getConf()))) { client = acquireLocalWorkerClient(address); if (client == null) { throw new IOException( ExceptionMessage.NO_WORKER_AVAILABLE_ON_ADDRESS.getMessage(address)); } } else { client = acquireRemoteWorkerClient(address); } return client; } /** * Obtains a worker client on the local worker in the system. For testing only. * * @return a {@link BlockWorkerClient} to a worker in the Alluxio system or null if failed */ public BlockWorkerClient acquireLocalWorkerClient() { initializeLocalBlockWorkerClientPool(); if (mLocalBlockWorkerClientPoolMap.isEmpty()) { return null; } // return any local worker return mLocalBlockWorkerClientPoolMap.values().iterator().next().acquire(); } /** * Obtains a worker client for the given local worker address. * * @param address worker address * * @return a {@link BlockWorkerClient} to the given worker address or null if no such worker can * be found */ public BlockWorkerClient acquireLocalWorkerClient(WorkerNetAddress address) { initializeLocalBlockWorkerClientPool(); if (!mLocalBlockWorkerClientPoolMap.containsKey(address)) { return null; } return mLocalBlockWorkerClientPoolMap.get(address).acquire(); } /** * Obtains a client for a remote based on the given network address. Illegal argument exception is * thrown if the hostname is the local hostname. Runtime exception is thrown if the client cannot * be created with a connection to the hostname. * * @param address the address of the worker * @return a worker client with a connection to the specified hostname */ private BlockWorkerClient acquireRemoteWorkerClient(WorkerNetAddress address) { // If we couldn't find a worker, crash. if (address == null) { // TODO(calvin): Better exception usage. throw new RuntimeException(ExceptionMessage.NO_WORKER_AVAILABLE.getMessage()); } Preconditions.checkArgument( !address.getHost().equals(NetworkAddressUtils.getLocalHostName(ClientContext.getConf())), PreconditionMessage.REMOTE_CLIENT_BUT_LOCAL_HOSTNAME); long clientId = IdUtils.getRandomNonNegativeLong(); return new BlockWorkerClient(address, ClientContext.getBlockClientExecutorService(), ClientContext.getConf(), clientId, false, new ClientMetrics()); } /** * Releases the {@link BlockWorkerClient} back to the client pool, or destroys it if it was a * remote client. * * @param blockWorkerClient the worker client to release, the client should not be accessed after * this method is called */ public void releaseWorkerClient(BlockWorkerClient blockWorkerClient) { // If the client is local and the pool exists, release the client to the pool, otherwise just // close the client. if (blockWorkerClient.isLocal()) { // Return local worker client to its resource pool. WorkerNetAddress address = blockWorkerClient.getWorkerNetAddress(); if (!mLocalBlockWorkerClientPoolMap.containsKey(address)) { LOG.error("The client to worker at {} to release is no longer registered in the context.", address); blockWorkerClient.close(); } else { mLocalBlockWorkerClientPoolMap.get(address).release(blockWorkerClient); } } else { // Destroy remote worker client. blockWorkerClient.close(); } } /** * @return if there is a local worker running the same machine */ public boolean hasLocalWorker() { initializeLocalBlockWorkerClientPool(); return !mLocalBlockWorkerClientPoolMap.isEmpty(); } /** * Re-initializes the {@link BlockStoreContext}. This method should only be used in * {@link ClientContext}. */ @SuppressFBWarnings public void reset() { if (mBlockMasterClientPool != null) { mBlockMasterClientPool.close(); } for (BlockWorkerClientPool pool : mLocalBlockWorkerClientPoolMap.values()) { pool.close(); } mLocalBlockWorkerClientPoolMap.clear(); mBlockMasterClientPool = new BlockMasterClientPool(ClientContext.getMasterAddress()); mLocalBlockWorkerClientPoolInitialized = false; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy