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 if (ugi == null) {
113 ugi = NameNode.getRemoteUser();
114 }
115 ownerName = ugi.getShortUserName();
116 }
117 String groupName = info.getGroupName();
118 if (groupName == null) {
119 if (ugi == null) {
120 ugi = NameNode.getRemoteUser();
121 }
122 groupName = ugi.getPrimaryGroupName();
123 }
124 FsPermission mode = (info.getMode() == null) ?
125 FsPermission.getCachePoolDefault() : info.getMode();
126 long limit = info.getLimit() == null ?
127 CachePoolInfo.DEFAULT_LIMIT : info.getLimit();
128 long maxRelativeExpiry = info.getMaxRelativeExpiryMs() == null ?
129 CachePoolInfo.DEFAULT_MAX_RELATIVE_EXPIRY :
130 info.getMaxRelativeExpiryMs();
131 return new CachePool(info.getPoolName(),
132 ownerName, groupName, mode, limit, maxRelativeExpiry);
133 }
134
135 /**
136 * Create a new cache pool based on a CachePoolInfo object.
137 * No fields in the CachePoolInfo can be blank.
138 */
139 static CachePool createFromInfo(CachePoolInfo info) {
140 return new CachePool(info.getPoolName(),
141 info.getOwnerName(), info.getGroupName(),
142 info.getMode(), info.getLimit(), info.getMaxRelativeExpiryMs());
143 }
144
145 CachePool(String poolName, String ownerName, String groupName,
146 FsPermission mode, long limit, long maxRelativeExpiry) {
147 Preconditions.checkNotNull(poolName);
148 Preconditions.checkNotNull(ownerName);
149 Preconditions.checkNotNull(groupName);
150 Preconditions.checkNotNull(mode);
151 this.poolName = poolName;
152 this.ownerName = ownerName;
153 this.groupName = groupName;
154 this.mode = new FsPermission(mode);
155 this.limit = limit;
156 this.maxRelativeExpiryMs = maxRelativeExpiry;
157 }
158
159 public String getPoolName() {
160 return poolName;
161 }
162
163 public String getOwnerName() {
164 return ownerName;
165 }
166
167 public CachePool setOwnerName(String ownerName) {
168 this.ownerName = ownerName;
169 return this;
170 }
171
172 public String getGroupName() {
173 return groupName;
174 }
175
176 public CachePool setGroupName(String groupName) {
177 this.groupName = groupName;
178 return this;
179 }
180
181 public FsPermission getMode() {
182 return mode;
183 }
184
185 public CachePool setMode(FsPermission mode) {
186 this.mode = new FsPermission(mode);
187 return this;
188 }
189
190 public long getLimit() {
191 return limit;
192 }
193
194 public CachePool setLimit(long bytes) {
195 this.limit = bytes;
196 return this;
197 }
198
199 public long getMaxRelativeExpiryMs() {
200 return maxRelativeExpiryMs;
201 }
202
203 public CachePool setMaxRelativeExpiryMs(long expiry) {
204 this.maxRelativeExpiryMs = expiry;
205 return this;
206 }
207
208 /**
209 * Get either full or partial information about this CachePool.
210 *
211 * @param fullInfo
212 * If true, only the name will be returned (i.e., what you
213 * would get if you didn't have read permission for this pool.)
214 * @return
215 * Cache pool information.
216 */
217 CachePoolInfo getInfo(boolean fullInfo) {
218 CachePoolInfo info = new CachePoolInfo(poolName);
219 if (!fullInfo) {
220 return info;
221 }
222 return info.setOwnerName(ownerName).
223 setGroupName(groupName).
224 setMode(new FsPermission(mode)).
225 setLimit(limit).
226 setMaxRelativeExpiryMs(maxRelativeExpiryMs);
227 }
228
229 /**
230 * Resets statistics related to this CachePool
231 */
232 public void resetStatistics() {
233 bytesNeeded = 0;
234 bytesCached = 0;
235 filesNeeded = 0;
236 filesCached = 0;
237 }
238
239 public void addBytesNeeded(long bytes) {
240 bytesNeeded += bytes;
241 }
242
243 public void addBytesCached(long bytes) {
244 bytesCached += bytes;
245 }
246
247 public void addFilesNeeded(long files) {
248 filesNeeded += files;
249 }
250
251 public void addFilesCached(long files) {
252 filesCached += files;
253 }
254
255 public long getBytesNeeded() {
256 return bytesNeeded;
257 }
258
259 public long getBytesCached() {
260 return bytesCached;
261 }
262
263 public long getBytesOverlimit() {
264 return Math.max(bytesNeeded-limit, 0);
265 }
266
267 public long getFilesNeeded() {
268 return filesNeeded;
269 }
270
271 public long getFilesCached() {
272 return filesCached;
273 }
274
275 /**
276 * Get statistics about this CachePool.
277 *
278 * @return Cache pool statistics.
279 */
280 private CachePoolStats getStats() {
281 return new CachePoolStats.Builder().
282 setBytesNeeded(bytesNeeded).
283 setBytesCached(bytesCached).
284 setBytesOverlimit(getBytesOverlimit()).
285 setFilesNeeded(filesNeeded).
286 setFilesCached(filesCached).
287 build();
288 }
289
290 /**
291 * Returns a CachePoolInfo describing this CachePool based on the permissions
292 * of the calling user. Unprivileged users will see only minimal descriptive
293 * information about the pool.
294 *
295 * @param pc Permission checker to be used to validate the user's permissions,
296 * or null
297 * @return CachePoolEntry describing this CachePool
298 */
299 public CachePoolEntry getEntry(FSPermissionChecker pc) {
300 boolean hasPermission = true;
301 if (pc != null) {
302 try {
303 pc.checkPermission(this, FsAction.READ);
304 } catch (AccessControlException e) {
305 hasPermission = false;
306 }
307 }
308 return new CachePoolEntry(getInfo(hasPermission),
309 hasPermission ? getStats() : new CachePoolStats.Builder().build());
310 }
311
312 public String toString() {
313 return new StringBuilder().
314 append("{ ").append("poolName:").append(poolName).
315 append(", ownerName:").append(ownerName).
316 append(", groupName:").append(groupName).
317 append(", mode:").append(mode).
318 append(", limit:").append(limit).
319 append(", maxRelativeExpiryMs:").append(maxRelativeExpiryMs).
320 append(" }").toString();
321 }
322
323 public DirectiveList getDirectiveList() {
324 return directiveList;
325 }
326 }