001 /**
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements. See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership. The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License. You may obtain a copy of the License at
009 *
010 * http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018 package org.apache.hadoop.hdfs.server.namenode;
019
020 import java.io.IOException;
021
022 import javax.annotation.Nonnull;
023
024 import org.apache.commons.logging.Log;
025 import org.apache.commons.logging.LogFactory;
026 import org.apache.hadoop.classification.InterfaceAudience;
027 import org.apache.hadoop.fs.permission.FsAction;
028 import org.apache.hadoop.fs.permission.FsPermission;
029 import org.apache.hadoop.hdfs.protocol.CacheDirective;
030 import org.apache.hadoop.hdfs.protocol.CachePoolEntry;
031 import org.apache.hadoop.hdfs.protocol.CachePoolInfo;
032 import org.apache.hadoop.hdfs.protocol.CachePoolStats;
033 import org.apache.hadoop.security.AccessControlException;
034 import org.apache.hadoop.security.UserGroupInformation;
035 import org.apache.hadoop.util.IntrusiveCollection;
036
037 import com.google.common.base.Preconditions;
038
039 /**
040 * A CachePool describes a set of cache resources being managed by the NameNode.
041 * User caching requests are billed to the cache pool specified in the request.
042 *
043 * This is an internal class, only used on the NameNode. For identifying or
044 * describing a cache pool to clients, please use CachePoolInfo.
045 *
046 * CachePools must be accessed under the FSNamesystem lock.
047 */
048 @InterfaceAudience.Private
049 public final class CachePool {
050 @Nonnull
051 private final String poolName;
052
053 @Nonnull
054 private String ownerName;
055
056 @Nonnull
057 private String groupName;
058
059 /**
060 * Cache pool permissions.
061 *
062 * READ permission means that you can list the cache directives in this pool.
063 * WRITE permission means that you can add, remove, or modify cache directives
064 * in this pool.
065 * EXECUTE permission is unused.
066 */
067 @Nonnull
068 private FsPermission mode;
069
070 /**
071 * Maximum number of bytes that can be cached in this pool.
072 */
073 private long limit;
074
075 /**
076 * Maximum duration that a CacheDirective in this pool remains valid,
077 * in milliseconds.
078 */
079 private long maxRelativeExpiryMs;
080
081 private long bytesNeeded;
082 private long bytesCached;
083 private long filesNeeded;
084 private long filesCached;
085
086 public final static class DirectiveList
087 extends IntrusiveCollection<CacheDirective> {
088 private final CachePool cachePool;
089
090 private DirectiveList(CachePool cachePool) {
091 this.cachePool = cachePool;
092 }
093
094 public CachePool getCachePool() {
095 return cachePool;
096 }
097 }
098
099 @Nonnull
100 private final DirectiveList directiveList = new DirectiveList(this);
101
102 /**
103 * Create a new cache pool based on a CachePoolInfo object and the defaults.
104 * We will fill in information that was not supplied according to the
105 * defaults.
106 */
107 static CachePool createFromInfoAndDefaults(CachePoolInfo info)
108 throws IOException {
109 UserGroupInformation ugi = null;
110 String ownerName = info.getOwnerName();
111 if (ownerName == null) {
112 ugi = NameNode.getRemoteUser();
113 ownerName = ugi.getShortUserName();
114 }
115 String groupName = info.getGroupName();
116 if (groupName == null) {
117 if (ugi == null) {
118 ugi = NameNode.getRemoteUser();
119 }
120 groupName = ugi.getPrimaryGroupName();
121 }
122 FsPermission mode = (info.getMode() == null) ?
123 FsPermission.getCachePoolDefault() : info.getMode();
124 long limit = info.getLimit() == null ?
125 CachePoolInfo.DEFAULT_LIMIT : info.getLimit();
126 long maxRelativeExpiry = info.getMaxRelativeExpiryMs() == null ?
127 CachePoolInfo.DEFAULT_MAX_RELATIVE_EXPIRY :
128 info.getMaxRelativeExpiryMs();
129 return new CachePool(info.getPoolName(),
130 ownerName, groupName, mode, limit, maxRelativeExpiry);
131 }
132
133 /**
134 * Create a new cache pool based on a CachePoolInfo object.
135 * No fields in the CachePoolInfo can be blank.
136 */
137 static CachePool createFromInfo(CachePoolInfo info) {
138 return new CachePool(info.getPoolName(),
139 info.getOwnerName(), info.getGroupName(),
140 info.getMode(), info.getLimit(), info.getMaxRelativeExpiryMs());
141 }
142
143 CachePool(String poolName, String ownerName, String groupName,
144 FsPermission mode, long limit, long maxRelativeExpiry) {
145 Preconditions.checkNotNull(poolName);
146 Preconditions.checkNotNull(ownerName);
147 Preconditions.checkNotNull(groupName);
148 Preconditions.checkNotNull(mode);
149 this.poolName = poolName;
150 this.ownerName = ownerName;
151 this.groupName = groupName;
152 this.mode = new FsPermission(mode);
153 this.limit = limit;
154 this.maxRelativeExpiryMs = maxRelativeExpiry;
155 }
156
157 public String getPoolName() {
158 return poolName;
159 }
160
161 public String getOwnerName() {
162 return ownerName;
163 }
164
165 public CachePool setOwnerName(String ownerName) {
166 this.ownerName = ownerName;
167 return this;
168 }
169
170 public String getGroupName() {
171 return groupName;
172 }
173
174 public CachePool setGroupName(String groupName) {
175 this.groupName = groupName;
176 return this;
177 }
178
179 public FsPermission getMode() {
180 return mode;
181 }
182
183 public CachePool setMode(FsPermission mode) {
184 this.mode = new FsPermission(mode);
185 return this;
186 }
187
188 public long getLimit() {
189 return limit;
190 }
191
192 public CachePool setLimit(long bytes) {
193 this.limit = bytes;
194 return this;
195 }
196
197 public long getMaxRelativeExpiryMs() {
198 return maxRelativeExpiryMs;
199 }
200
201 public CachePool setMaxRelativeExpiryMs(long expiry) {
202 this.maxRelativeExpiryMs = expiry;
203 return this;
204 }
205
206 /**
207 * Get either full or partial information about this CachePool.
208 *
209 * @param fullInfo
210 * If true, only the name will be returned (i.e., what you
211 * would get if you didn't have read permission for this pool.)
212 * @return
213 * Cache pool information.
214 */
215 CachePoolInfo getInfo(boolean fullInfo) {
216 CachePoolInfo info = new CachePoolInfo(poolName);
217 if (!fullInfo) {
218 return info;
219 }
220 return info.setOwnerName(ownerName).
221 setGroupName(groupName).
222 setMode(new FsPermission(mode)).
223 setLimit(limit).
224 setMaxRelativeExpiryMs(maxRelativeExpiryMs);
225 }
226
227 /**
228 * Resets statistics related to this CachePool
229 */
230 public void resetStatistics() {
231 bytesNeeded = 0;
232 bytesCached = 0;
233 filesNeeded = 0;
234 filesCached = 0;
235 }
236
237 public void addBytesNeeded(long bytes) {
238 bytesNeeded += bytes;
239 }
240
241 public void addBytesCached(long bytes) {
242 bytesCached += bytes;
243 }
244
245 public void addFilesNeeded(long files) {
246 filesNeeded += files;
247 }
248
249 public void addFilesCached(long files) {
250 filesCached += files;
251 }
252
253 public long getBytesNeeded() {
254 return bytesNeeded;
255 }
256
257 public long getBytesCached() {
258 return bytesCached;
259 }
260
261 public long getBytesOverlimit() {
262 return Math.max(bytesNeeded-limit, 0);
263 }
264
265 public long getFilesNeeded() {
266 return filesNeeded;
267 }
268
269 public long getFilesCached() {
270 return filesCached;
271 }
272
273 /**
274 * Get statistics about this CachePool.
275 *
276 * @return Cache pool statistics.
277 */
278 private CachePoolStats getStats() {
279 return new CachePoolStats.Builder().
280 setBytesNeeded(bytesNeeded).
281 setBytesCached(bytesCached).
282 setBytesOverlimit(getBytesOverlimit()).
283 setFilesNeeded(filesNeeded).
284 setFilesCached(filesCached).
285 build();
286 }
287
288 /**
289 * Returns a CachePoolInfo describing this CachePool based on the permissions
290 * of the calling user. Unprivileged users will see only minimal descriptive
291 * information about the pool.
292 *
293 * @param pc Permission checker to be used to validate the user's permissions,
294 * or null
295 * @return CachePoolEntry describing this CachePool
296 */
297 public CachePoolEntry getEntry(FSPermissionChecker pc) {
298 boolean hasPermission = true;
299 if (pc != null) {
300 try {
301 pc.checkPermission(this, FsAction.READ);
302 } catch (AccessControlException e) {
303 hasPermission = false;
304 }
305 }
306 return new CachePoolEntry(getInfo(hasPermission),
307 hasPermission ? getStats() : new CachePoolStats.Builder().build());
308 }
309
310 public String toString() {
311 return new StringBuilder().
312 append("{ ").append("poolName:").append(poolName).
313 append(", ownerName:").append(ownerName).
314 append(", groupName:").append(groupName).
315 append(", mode:").append(mode).
316 append(", limit:").append(limit).
317 append(", maxRelativeExpiryMs:").append(maxRelativeExpiryMs).
318 append(" }").toString();
319 }
320
321 public DirectiveList getDirectiveList() {
322 return directiveList;
323 }
324 }