/** * 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.hadoop.hdfs.server.namenode; import java.io.IOException; import javax.annotation.Nonnull; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.hadoop.classification.InterfaceAudience; import org.apache.hadoop.fs.permission.FsAction; import org.apache.hadoop.fs.permission.FsPermission; import org.apache.hadoop.hdfs.protocol.CacheDirective; import org.apache.hadoop.hdfs.protocol.CachePoolEntry; import org.apache.hadoop.hdfs.protocol.CachePoolInfo; import org.apache.hadoop.hdfs.protocol.CachePoolStats; import org.apache.hadoop.security.AccessControlException; import org.apache.hadoop.security.UserGroupInformation; import org.apache.hadoop.util.IntrusiveCollection; import com.google.common.base.Preconditions; /** * A CachePool describes a set of cache resources being managed by the NameNode. * User caching requests are billed to the cache pool specified in the request. * * This is an internal class, only used on the NameNode. For identifying or * describing a cache pool to clients, please use CachePoolInfo. * * CachePools must be accessed under the FSNamesystem lock. */ @InterfaceAudience.Private public final class CachePool { @Nonnull private final String poolName; @Nonnull private String ownerName; @Nonnull private String groupName; /** * Cache pool permissions. * * READ permission means that you can list the cache directives in this pool. * WRITE permission means that you can add, remove, or modify cache directives * in this pool. * EXECUTE permission is unused. */ @Nonnull private FsPermission mode; /** * Maximum number of bytes that can be cached in this pool. */ private long limit; /** * Maximum duration that a CacheDirective in this pool remains valid, * in milliseconds. */ private long maxRelativeExpiryMs; private long bytesNeeded; private long bytesCached; private long filesNeeded; private long filesCached; public final static class DirectiveList extends IntrusiveCollection<CacheDirective> { private final CachePool cachePool; private DirectiveList(CachePool cachePool) { this.cachePool = cachePool; } public CachePool getCachePool() { return cachePool; } } @Nonnull private final DirectiveList directiveList = new DirectiveList(this); /** * Create a new cache pool based on a CachePoolInfo object and the defaults. * We will fill in information that was not supplied according to the * defaults. */ static CachePool createFromInfoAndDefaults(CachePoolInfo info) throws IOException { UserGroupInformation ugi = null; String ownerName = info.getOwnerName(); if (ownerName == null) { if (ugi == null) { ugi = NameNode.getRemoteUser(); } ownerName = ugi.getShortUserName(); } String groupName = info.getGroupName(); if (groupName == null) { if (ugi == null) { ugi = NameNode.getRemoteUser(); } groupName = ugi.getPrimaryGroupName(); } FsPermission mode = (info.getMode() == null) ? FsPermission.getCachePoolDefault() : info.getMode(); long limit = info.getLimit() == null ? CachePoolInfo.DEFAULT_LIMIT : info.getLimit(); long maxRelativeExpiry = info.getMaxRelativeExpiryMs() == null ? CachePoolInfo.DEFAULT_MAX_RELATIVE_EXPIRY : info.getMaxRelativeExpiryMs(); return new CachePool(info.getPoolName(), ownerName, groupName, mode, limit, maxRelativeExpiry); } /** * Create a new cache pool based on a CachePoolInfo object. * No fields in the CachePoolInfo can be blank. */ static CachePool createFromInfo(CachePoolInfo info) { return new CachePool(info.getPoolName(), info.getOwnerName(), info.getGroupName(), info.getMode(), info.getLimit(), info.getMaxRelativeExpiryMs()); } CachePool(String poolName, String ownerName, String groupName, FsPermission mode, long limit, long maxRelativeExpiry) { Preconditions.checkNotNull(poolName); Preconditions.checkNotNull(ownerName); Preconditions.checkNotNull(groupName); Preconditions.checkNotNull(mode); this.poolName = poolName; this.ownerName = ownerName; this.groupName = groupName; this.mode = new FsPermission(mode); this.limit = limit; this.maxRelativeExpiryMs = maxRelativeExpiry; } public String getPoolName() { return poolName; } public String getOwnerName() { return ownerName; } public CachePool setOwnerName(String ownerName) { this.ownerName = ownerName; return this; } public String getGroupName() { return groupName; } public CachePool setGroupName(String groupName) { this.groupName = groupName; return this; } public FsPermission getMode() { return mode; } public CachePool setMode(FsPermission mode) { this.mode = new FsPermission(mode); return this; } public long getLimit() { return limit; } public CachePool setLimit(long bytes) { this.limit = bytes; return this; } public long getMaxRelativeExpiryMs() { return maxRelativeExpiryMs; } public CachePool setMaxRelativeExpiryMs(long expiry) { this.maxRelativeExpiryMs = expiry; return this; } /** * Get either full or partial information about this CachePool. * * @param fullInfo * If true, only the name will be returned (i.e., what you * would get if you didn't have read permission for this pool.) * @return * Cache pool information. */ CachePoolInfo getInfo(boolean fullInfo) { CachePoolInfo info = new CachePoolInfo(poolName); if (!fullInfo) { return info; } return info.setOwnerName(ownerName). setGroupName(groupName). setMode(new FsPermission(mode)). setLimit(limit). setMaxRelativeExpiryMs(maxRelativeExpiryMs); } /** * Resets statistics related to this CachePool */ public void resetStatistics() { bytesNeeded = 0; bytesCached = 0; filesNeeded = 0; filesCached = 0; } public void addBytesNeeded(long bytes) { bytesNeeded += bytes; } public void addBytesCached(long bytes) { bytesCached += bytes; } public void addFilesNeeded(long files) { filesNeeded += files; } public void addFilesCached(long files) { filesCached += files; } public long getBytesNeeded() { return bytesNeeded; } public long getBytesCached() { return bytesCached; } public long getBytesOverlimit() { return Math.max(bytesNeeded-limit, 0); } public long getFilesNeeded() { return filesNeeded; } public long getFilesCached() { return filesCached; } /** * Get statistics about this CachePool. * * @return Cache pool statistics. */ private CachePoolStats getStats() { return new CachePoolStats.Builder(). setBytesNeeded(bytesNeeded). setBytesCached(bytesCached). setBytesOverlimit(getBytesOverlimit()). setFilesNeeded(filesNeeded). setFilesCached(filesCached). build(); } /** * Returns a CachePoolInfo describing this CachePool based on the permissions * of the calling user. Unprivileged users will see only minimal descriptive * information about the pool. * * @param pc Permission checker to be used to validate the user's permissions, * or null * @return CachePoolEntry describing this CachePool */ public CachePoolEntry getEntry(FSPermissionChecker pc) { boolean hasPermission = true; if (pc != null) { try { pc.checkPermission(this, FsAction.READ); } catch (AccessControlException e) { hasPermission = false; } } return new CachePoolEntry(getInfo(hasPermission), hasPermission ? getStats() : new CachePoolStats.Builder().build()); } public String toString() { return new StringBuilder(). append("{ ").append("poolName:").append(poolName). append(", ownerName:").append(ownerName). append(", groupName:").append(groupName). append(", mode:").append(mode). append(", limit:").append(limit). append(", maxRelativeExpiryMs:").append(maxRelativeExpiryMs). append(" }").toString(); } public DirectiveList getDirectiveList() { return directiveList; } }