1 /** 2 * Licensed to the Apache Software Foundation (ASF) under one 3 * or more contributor license agreements. See the NOTICE file 4 * distributed with this work for additional information 5 * regarding copyright ownership. The ASF licenses this file 6 * to you under the Apache License, Version 2.0 (the 7 * "License"); you may not use this file except in compliance 8 * with the License. You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 */ 18 package org.apache.hadoop.hdfs.tools; 19 20 import java.io.IOException; 21 import java.util.EnumSet; 22 import java.util.LinkedList; 23 import java.util.List; 24 25 import org.apache.commons.lang.WordUtils; 26 import org.apache.hadoop.classification.InterfaceAudience; 27 import org.apache.hadoop.conf.Configuration; 28 import org.apache.hadoop.conf.Configured; 29 import org.apache.hadoop.fs.CacheFlag; 30 import org.apache.hadoop.fs.Path; 31 import org.apache.hadoop.fs.RemoteIterator; 32 import org.apache.hadoop.fs.permission.FsPermission; 33 import org.apache.hadoop.hdfs.DFSUtil; 34 import org.apache.hadoop.hdfs.DistributedFileSystem; 35 import org.apache.hadoop.hdfs.protocol.CacheDirectiveEntry; 36 import org.apache.hadoop.hdfs.protocol.CacheDirectiveInfo; 37 import org.apache.hadoop.hdfs.protocol.CacheDirectiveInfo.Expiration; 38 import org.apache.hadoop.hdfs.protocol.CacheDirectiveStats; 39 import org.apache.hadoop.hdfs.protocol.CachePoolEntry; 40 import org.apache.hadoop.hdfs.protocol.CachePoolInfo; 41 import org.apache.hadoop.hdfs.protocol.CachePoolStats; 42 import org.apache.hadoop.tools.TableListing; 43 import org.apache.hadoop.tools.TableListing.Justification; 44 import org.apache.hadoop.util.StringUtils; 45 import org.apache.hadoop.util.Tool; 46 47 import com.google.common.base.Joiner; 48 49 /** 50 * This class implements command-line operations on the HDFS Cache. 51 */ 52 @InterfaceAudience.Private 53 public class CacheAdmin extends Configured implements Tool { 54 CacheAdmin()55 public CacheAdmin() { 56 this(null); 57 } 58 CacheAdmin(Configuration conf)59 public CacheAdmin(Configuration conf) { 60 super(conf); 61 } 62 63 @Override run(String[] args)64 public int run(String[] args) throws IOException { 65 if (args.length == 0) { 66 AdminHelper.printUsage(false, "cacheadmin", COMMANDS); 67 return 1; 68 } 69 AdminHelper.Command command = AdminHelper.determineCommand(args[0], 70 COMMANDS); 71 if (command == null) { 72 System.err.println("Can't understand command '" + args[0] + "'"); 73 if (!args[0].startsWith("-")) { 74 System.err.println("Command names must start with dashes."); 75 } 76 AdminHelper.printUsage(false, "cacheadmin", COMMANDS); 77 return 1; 78 } 79 List<String> argsList = new LinkedList<String>(); 80 for (int j = 1; j < args.length; j++) { 81 argsList.add(args[j]); 82 } 83 try { 84 return command.run(getConf(), argsList); 85 } catch (IllegalArgumentException e) { 86 System.err.println(AdminHelper.prettifyException(e)); 87 return -1; 88 } 89 } 90 main(String[] argsArray)91 public static void main(String[] argsArray) throws IOException { 92 CacheAdmin cacheAdmin = new CacheAdmin(new Configuration()); 93 System.exit(cacheAdmin.run(argsArray)); 94 } 95 parseExpirationString(String ttlString)96 private static CacheDirectiveInfo.Expiration parseExpirationString(String ttlString) 97 throws IOException { 98 CacheDirectiveInfo.Expiration ex = null; 99 if (ttlString != null) { 100 if (ttlString.equalsIgnoreCase("never")) { 101 ex = CacheDirectiveInfo.Expiration.NEVER; 102 } else { 103 long ttl = DFSUtil.parseRelativeTime(ttlString); 104 ex = CacheDirectiveInfo.Expiration.newRelative(ttl); 105 } 106 } 107 return ex; 108 } 109 110 private static class AddCacheDirectiveInfoCommand 111 implements AdminHelper.Command { 112 @Override getName()113 public String getName() { 114 return "-addDirective"; 115 } 116 117 @Override getShortUsage()118 public String getShortUsage() { 119 return "[" + getName() + 120 " -path <path> -pool <pool-name> " + 121 "[-force] " + 122 "[-replication <replication>] [-ttl <time-to-live>]]\n"; 123 } 124 125 @Override getLongUsage()126 public String getLongUsage() { 127 TableListing listing = AdminHelper.getOptionDescriptionListing(); 128 listing.addRow("<path>", "A path to cache. The path can be " + 129 "a directory or a file."); 130 listing.addRow("<pool-name>", "The pool to which the directive will be " + 131 "added. You must have write permission on the cache pool " 132 + "in order to add new directives."); 133 listing.addRow("-force", 134 "Skips checking of cache pool resource limits."); 135 listing.addRow("<replication>", "The cache replication factor to use. " + 136 "Defaults to 1."); 137 listing.addRow("<time-to-live>", "How long the directive is " + 138 "valid. Can be specified in minutes, hours, and days, e.g. " + 139 "30m, 4h, 2d. Valid units are [smhd]." + 140 " \"never\" indicates a directive that never expires." + 141 " If unspecified, the directive never expires."); 142 return getShortUsage() + "\n" + 143 "Add a new cache directive.\n\n" + 144 listing.toString(); 145 } 146 147 @Override run(Configuration conf, List<String> args)148 public int run(Configuration conf, List<String> args) throws IOException { 149 CacheDirectiveInfo.Builder builder = new CacheDirectiveInfo.Builder(); 150 151 String path = StringUtils.popOptionWithArgument("-path", args); 152 if (path == null) { 153 System.err.println("You must specify a path with -path."); 154 return 1; 155 } 156 builder.setPath(new Path(path)); 157 158 String poolName = StringUtils.popOptionWithArgument("-pool", args); 159 if (poolName == null) { 160 System.err.println("You must specify a pool name with -pool."); 161 return 1; 162 } 163 builder.setPool(poolName); 164 boolean force = StringUtils.popOption("-force", args); 165 String replicationString = 166 StringUtils.popOptionWithArgument("-replication", args); 167 if (replicationString != null) { 168 Short replication = Short.parseShort(replicationString); 169 builder.setReplication(replication); 170 } 171 172 String ttlString = StringUtils.popOptionWithArgument("-ttl", args); 173 try { 174 Expiration ex = parseExpirationString(ttlString); 175 if (ex != null) { 176 builder.setExpiration(ex); 177 } 178 } catch (IOException e) { 179 System.err.println( 180 "Error while parsing ttl value: " + e.getMessage()); 181 return 1; 182 } 183 184 if (!args.isEmpty()) { 185 System.err.println("Can't understand argument: " + args.get(0)); 186 return 1; 187 } 188 189 DistributedFileSystem dfs = AdminHelper.getDFS(conf); 190 CacheDirectiveInfo directive = builder.build(); 191 EnumSet<CacheFlag> flags = EnumSet.noneOf(CacheFlag.class); 192 if (force) { 193 flags.add(CacheFlag.FORCE); 194 } 195 try { 196 long id = dfs.addCacheDirective(directive, flags); 197 System.out.println("Added cache directive " + id); 198 } catch (IOException e) { 199 System.err.println(AdminHelper.prettifyException(e)); 200 return 2; 201 } 202 203 return 0; 204 } 205 } 206 207 private static class RemoveCacheDirectiveInfoCommand 208 implements AdminHelper.Command { 209 @Override getName()210 public String getName() { 211 return "-removeDirective"; 212 } 213 214 @Override getShortUsage()215 public String getShortUsage() { 216 return "[" + getName() + " <id>]\n"; 217 } 218 219 @Override getLongUsage()220 public String getLongUsage() { 221 TableListing listing = AdminHelper.getOptionDescriptionListing(); 222 listing.addRow("<id>", "The id of the cache directive to remove. " + 223 "You must have write permission on the pool of the " + 224 "directive in order to remove it. To see a list " + 225 "of cache directive IDs, use the -listDirectives command."); 226 return getShortUsage() + "\n" + 227 "Remove a cache directive.\n\n" + 228 listing.toString(); 229 } 230 231 @Override run(Configuration conf, List<String> args)232 public int run(Configuration conf, List<String> args) throws IOException { 233 String idString= StringUtils.popFirstNonOption(args); 234 if (idString == null) { 235 System.err.println("You must specify a directive ID to remove."); 236 return 1; 237 } 238 long id; 239 try { 240 id = Long.parseLong(idString); 241 } catch (NumberFormatException e) { 242 System.err.println("Invalid directive ID " + idString + ": expected " + 243 "a numeric value."); 244 return 1; 245 } 246 if (id <= 0) { 247 System.err.println("Invalid directive ID " + id + ": ids must " + 248 "be greater than 0."); 249 return 1; 250 } 251 if (!args.isEmpty()) { 252 System.err.println("Can't understand argument: " + args.get(0)); 253 System.err.println("Usage is " + getShortUsage()); 254 return 1; 255 } 256 DistributedFileSystem dfs = AdminHelper.getDFS(conf); 257 try { 258 dfs.getClient().removeCacheDirective(id); 259 System.out.println("Removed cached directive " + id); 260 } catch (IOException e) { 261 System.err.println(AdminHelper.prettifyException(e)); 262 return 2; 263 } 264 return 0; 265 } 266 } 267 268 private static class ModifyCacheDirectiveInfoCommand 269 implements AdminHelper.Command { 270 @Override getName()271 public String getName() { 272 return "-modifyDirective"; 273 } 274 275 @Override getShortUsage()276 public String getShortUsage() { 277 return "[" + getName() + 278 " -id <id> [-path <path>] [-force] [-replication <replication>] " + 279 "[-pool <pool-name>] [-ttl <time-to-live>]]\n"; 280 } 281 282 @Override getLongUsage()283 public String getLongUsage() { 284 TableListing listing = AdminHelper.getOptionDescriptionListing(); 285 listing.addRow("<id>", "The ID of the directive to modify (required)"); 286 listing.addRow("<path>", "A path to cache. The path can be " + 287 "a directory or a file. (optional)"); 288 listing.addRow("-force", 289 "Skips checking of cache pool resource limits."); 290 listing.addRow("<replication>", "The cache replication factor to use. " + 291 "(optional)"); 292 listing.addRow("<pool-name>", "The pool to which the directive will be " + 293 "added. You must have write permission on the cache pool " 294 + "in order to move a directive into it. (optional)"); 295 listing.addRow("<time-to-live>", "How long the directive is " + 296 "valid. Can be specified in minutes, hours, and days, e.g. " + 297 "30m, 4h, 2d. Valid units are [smhd]." + 298 " \"never\" indicates a directive that never expires."); 299 return getShortUsage() + "\n" + 300 "Modify a cache directive.\n\n" + 301 listing.toString(); 302 } 303 304 @Override run(Configuration conf, List<String> args)305 public int run(Configuration conf, List<String> args) throws IOException { 306 CacheDirectiveInfo.Builder builder = 307 new CacheDirectiveInfo.Builder(); 308 boolean modified = false; 309 String idString = StringUtils.popOptionWithArgument("-id", args); 310 if (idString == null) { 311 System.err.println("You must specify a directive ID with -id."); 312 return 1; 313 } 314 builder.setId(Long.parseLong(idString)); 315 String path = StringUtils.popOptionWithArgument("-path", args); 316 if (path != null) { 317 builder.setPath(new Path(path)); 318 modified = true; 319 } 320 boolean force = StringUtils.popOption("-force", args); 321 String replicationString = 322 StringUtils.popOptionWithArgument("-replication", args); 323 if (replicationString != null) { 324 builder.setReplication(Short.parseShort(replicationString)); 325 modified = true; 326 } 327 String poolName = 328 StringUtils.popOptionWithArgument("-pool", args); 329 if (poolName != null) { 330 builder.setPool(poolName); 331 modified = true; 332 } 333 String ttlString = StringUtils.popOptionWithArgument("-ttl", args); 334 try { 335 Expiration ex = parseExpirationString(ttlString); 336 if (ex != null) { 337 builder.setExpiration(ex); 338 modified = true; 339 } 340 } catch (IOException e) { 341 System.err.println( 342 "Error while parsing ttl value: " + e.getMessage()); 343 return 1; 344 } 345 if (!args.isEmpty()) { 346 System.err.println("Can't understand argument: " + args.get(0)); 347 System.err.println("Usage is " + getShortUsage()); 348 return 1; 349 } 350 if (!modified) { 351 System.err.println("No modifications were specified."); 352 return 1; 353 } 354 DistributedFileSystem dfs = AdminHelper.getDFS(conf); 355 EnumSet<CacheFlag> flags = EnumSet.noneOf(CacheFlag.class); 356 if (force) { 357 flags.add(CacheFlag.FORCE); 358 } 359 try { 360 dfs.modifyCacheDirective(builder.build(), flags); 361 System.out.println("Modified cache directive " + idString); 362 } catch (IOException e) { 363 System.err.println(AdminHelper.prettifyException(e)); 364 return 2; 365 } 366 return 0; 367 } 368 } 369 370 private static class RemoveCacheDirectiveInfosCommand 371 implements AdminHelper.Command { 372 @Override getName()373 public String getName() { 374 return "-removeDirectives"; 375 } 376 377 @Override getShortUsage()378 public String getShortUsage() { 379 return "[" + getName() + " -path <path>]\n"; 380 } 381 382 @Override getLongUsage()383 public String getLongUsage() { 384 TableListing listing = AdminHelper.getOptionDescriptionListing(); 385 listing.addRow("-path <path>", "The path of the cache directives to remove. " + 386 "You must have write permission on the pool of the directive in order " + 387 "to remove it. To see a list of cache directives, use the " + 388 "-listDirectives command."); 389 return getShortUsage() + "\n" + 390 "Remove every cache directive with the specified path.\n\n" + 391 listing.toString(); 392 } 393 394 @Override run(Configuration conf, List<String> args)395 public int run(Configuration conf, List<String> args) throws IOException { 396 String path = StringUtils.popOptionWithArgument("-path", args); 397 if (path == null) { 398 System.err.println("You must specify a path with -path."); 399 return 1; 400 } 401 if (!args.isEmpty()) { 402 System.err.println("Can't understand argument: " + args.get(0)); 403 System.err.println("Usage is " + getShortUsage()); 404 return 1; 405 } 406 int exitCode = 0; 407 try { 408 DistributedFileSystem dfs = AdminHelper.getDFS(conf); 409 RemoteIterator<CacheDirectiveEntry> iter = 410 dfs.listCacheDirectives( 411 new CacheDirectiveInfo.Builder(). 412 setPath(new Path(path)).build()); 413 while (iter.hasNext()) { 414 CacheDirectiveEntry entry = iter.next(); 415 try { 416 dfs.removeCacheDirective(entry.getInfo().getId()); 417 System.out.println("Removed cache directive " + 418 entry.getInfo().getId()); 419 } catch (IOException e) { 420 System.err.println(AdminHelper.prettifyException(e)); 421 exitCode = 2; 422 } 423 } 424 } catch (IOException e) { 425 System.err.println(AdminHelper.prettifyException(e)); 426 exitCode = 2; 427 } 428 if (exitCode == 0) { 429 System.out.println("Removed every cache directive with path " + 430 path); 431 } 432 return exitCode; 433 } 434 } 435 436 private static class ListCacheDirectiveInfoCommand 437 implements AdminHelper.Command { 438 @Override getName()439 public String getName() { 440 return "-listDirectives"; 441 } 442 443 @Override getShortUsage()444 public String getShortUsage() { 445 return "[" + getName() 446 + " [-stats] [-path <path>] [-pool <pool>] [-id <id>]\n"; 447 } 448 449 @Override getLongUsage()450 public String getLongUsage() { 451 TableListing listing = AdminHelper.getOptionDescriptionListing(); 452 listing.addRow("-stats", "List path-based cache directive statistics."); 453 listing.addRow("<path>", "List only " + 454 "cache directives with this path. " + 455 "Note that if there is a cache directive for <path> " + 456 "in a cache pool that we don't have read access for, it " + 457 "will not be listed."); 458 listing.addRow("<pool>", "List only path cache directives in that pool."); 459 listing.addRow("<id>", "List the cache directive with this id."); 460 return getShortUsage() + "\n" + 461 "List cache directives.\n\n" + 462 listing.toString(); 463 } 464 465 @Override run(Configuration conf, List<String> args)466 public int run(Configuration conf, List<String> args) throws IOException { 467 CacheDirectiveInfo.Builder builder = 468 new CacheDirectiveInfo.Builder(); 469 String pathFilter = StringUtils.popOptionWithArgument("-path", args); 470 if (pathFilter != null) { 471 builder.setPath(new Path(pathFilter)); 472 } 473 String poolFilter = StringUtils.popOptionWithArgument("-pool", args); 474 if (poolFilter != null) { 475 builder.setPool(poolFilter); 476 } 477 boolean printStats = StringUtils.popOption("-stats", args); 478 String idFilter = StringUtils.popOptionWithArgument("-id", args); 479 if (idFilter != null) { 480 builder.setId(Long.parseLong(idFilter)); 481 } 482 if (!args.isEmpty()) { 483 System.err.println("Can't understand argument: " + args.get(0)); 484 return 1; 485 } 486 TableListing.Builder tableBuilder = new TableListing.Builder(). 487 addField("ID", Justification.RIGHT). 488 addField("POOL", Justification.LEFT). 489 addField("REPL", Justification.RIGHT). 490 addField("EXPIRY", Justification.LEFT). 491 addField("PATH", Justification.LEFT); 492 if (printStats) { 493 tableBuilder.addField("BYTES_NEEDED", Justification.RIGHT). 494 addField("BYTES_CACHED", Justification.RIGHT). 495 addField("FILES_NEEDED", Justification.RIGHT). 496 addField("FILES_CACHED", Justification.RIGHT); 497 } 498 TableListing tableListing = tableBuilder.build(); 499 try { 500 DistributedFileSystem dfs = AdminHelper.getDFS(conf); 501 RemoteIterator<CacheDirectiveEntry> iter = 502 dfs.listCacheDirectives(builder.build()); 503 int numEntries = 0; 504 while (iter.hasNext()) { 505 CacheDirectiveEntry entry = iter.next(); 506 CacheDirectiveInfo directive = entry.getInfo(); 507 CacheDirectiveStats stats = entry.getStats(); 508 List<String> row = new LinkedList<String>(); 509 row.add("" + directive.getId()); 510 row.add(directive.getPool()); 511 row.add("" + directive.getReplication()); 512 String expiry; 513 // This is effectively never, round for nice printing 514 if (directive.getExpiration().getMillis() > 515 Expiration.MAX_RELATIVE_EXPIRY_MS / 2) { 516 expiry = "never"; 517 } else { 518 expiry = directive.getExpiration().toString(); 519 } 520 row.add(expiry); 521 row.add(directive.getPath().toUri().getPath()); 522 if (printStats) { 523 row.add("" + stats.getBytesNeeded()); 524 row.add("" + stats.getBytesCached()); 525 row.add("" + stats.getFilesNeeded()); 526 row.add("" + stats.getFilesCached()); 527 } 528 tableListing.addRow(row.toArray(new String[row.size()])); 529 numEntries++; 530 } 531 System.out.print(String.format("Found %d entr%s%n", 532 numEntries, numEntries == 1 ? "y" : "ies")); 533 if (numEntries > 0) { 534 System.out.print(tableListing); 535 } 536 } catch (IOException e) { 537 System.err.println(AdminHelper.prettifyException(e)); 538 return 2; 539 } 540 return 0; 541 } 542 } 543 544 private static class AddCachePoolCommand implements AdminHelper.Command { 545 546 private static final String NAME = "-addPool"; 547 548 @Override getName()549 public String getName() { 550 return NAME; 551 } 552 553 @Override getShortUsage()554 public String getShortUsage() { 555 return "[" + NAME + " <name> [-owner <owner>] " + 556 "[-group <group>] [-mode <mode>] [-limit <limit>] " + 557 "[-maxTtl <maxTtl>]\n"; 558 } 559 560 @Override getLongUsage()561 public String getLongUsage() { 562 TableListing listing = AdminHelper.getOptionDescriptionListing(); 563 564 listing.addRow("<name>", "Name of the new pool."); 565 listing.addRow("<owner>", "Username of the owner of the pool. " + 566 "Defaults to the current user."); 567 listing.addRow("<group>", "Group of the pool. " + 568 "Defaults to the primary group name of the current user."); 569 listing.addRow("<mode>", "UNIX-style permissions for the pool. " + 570 "Permissions are specified in octal, e.g. 0755. " + 571 "By default, this is set to " + String.format("0%03o", 572 FsPermission.getCachePoolDefault().toShort()) + "."); 573 listing.addRow("<limit>", "The maximum number of bytes that can be " + 574 "cached by directives in this pool, in aggregate. By default, " + 575 "no limit is set."); 576 listing.addRow("<maxTtl>", "The maximum allowed time-to-live for " + 577 "directives being added to the pool. This can be specified in " + 578 "seconds, minutes, hours, and days, e.g. 120s, 30m, 4h, 2d. " + 579 "Valid units are [smhd]. By default, no maximum is set. " + 580 "A value of \"never\" specifies that there is no limit."); 581 return getShortUsage() + "\n" + 582 "Add a new cache pool.\n\n" + 583 listing.toString(); 584 } 585 586 @Override run(Configuration conf, List<String> args)587 public int run(Configuration conf, List<String> args) throws IOException { 588 String name = StringUtils.popFirstNonOption(args); 589 if (name == null) { 590 System.err.println("You must specify a name when creating a " + 591 "cache pool."); 592 return 1; 593 } 594 CachePoolInfo info = new CachePoolInfo(name); 595 596 String owner = StringUtils.popOptionWithArgument("-owner", args); 597 if (owner != null) { 598 info.setOwnerName(owner); 599 } 600 String group = StringUtils.popOptionWithArgument("-group", args); 601 if (group != null) { 602 info.setGroupName(group); 603 } 604 String modeString = StringUtils.popOptionWithArgument("-mode", args); 605 if (modeString != null) { 606 short mode = Short.parseShort(modeString, 8); 607 info.setMode(new FsPermission(mode)); 608 } 609 String limitString = StringUtils.popOptionWithArgument("-limit", args); 610 Long limit = AdminHelper.parseLimitString(limitString); 611 if (limit != null) { 612 info.setLimit(limit); 613 } 614 String maxTtlString = StringUtils.popOptionWithArgument("-maxTtl", args); 615 try { 616 Long maxTtl = AdminHelper.parseTtlString(maxTtlString); 617 if (maxTtl != null) { 618 info.setMaxRelativeExpiryMs(maxTtl); 619 } 620 } catch (IOException e) { 621 System.err.println( 622 "Error while parsing maxTtl value: " + e.getMessage()); 623 return 1; 624 } 625 626 if (!args.isEmpty()) { 627 System.err.print("Can't understand arguments: " + 628 Joiner.on(" ").join(args) + "\n"); 629 System.err.println("Usage is " + getShortUsage()); 630 return 1; 631 } 632 DistributedFileSystem dfs = AdminHelper.getDFS(conf); 633 try { 634 dfs.addCachePool(info); 635 } catch (IOException e) { 636 System.err.println(AdminHelper.prettifyException(e)); 637 return 2; 638 } 639 System.out.println("Successfully added cache pool " + name + "."); 640 return 0; 641 } 642 } 643 644 private static class ModifyCachePoolCommand implements AdminHelper.Command { 645 646 @Override getName()647 public String getName() { 648 return "-modifyPool"; 649 } 650 651 @Override getShortUsage()652 public String getShortUsage() { 653 return "[" + getName() + " <name> [-owner <owner>] " + 654 "[-group <group>] [-mode <mode>] [-limit <limit>] " + 655 "[-maxTtl <maxTtl>]]\n"; 656 } 657 658 @Override getLongUsage()659 public String getLongUsage() { 660 TableListing listing = AdminHelper.getOptionDescriptionListing(); 661 662 listing.addRow("<name>", "Name of the pool to modify."); 663 listing.addRow("<owner>", "Username of the owner of the pool"); 664 listing.addRow("<group>", "Groupname of the group of the pool."); 665 listing.addRow("<mode>", "Unix-style permissions of the pool in octal."); 666 listing.addRow("<limit>", "Maximum number of bytes that can be cached " + 667 "by this pool."); 668 listing.addRow("<maxTtl>", "The maximum allowed time-to-live for " + 669 "directives being added to the pool."); 670 671 return getShortUsage() + "\n" + 672 WordUtils.wrap("Modifies the metadata of an existing cache pool. " + 673 "See usage of " + AddCachePoolCommand.NAME + " for more details.", 674 AdminHelper.MAX_LINE_WIDTH) + "\n\n" + 675 listing.toString(); 676 } 677 678 @Override run(Configuration conf, List<String> args)679 public int run(Configuration conf, List<String> args) throws IOException { 680 String owner = StringUtils.popOptionWithArgument("-owner", args); 681 String group = StringUtils.popOptionWithArgument("-group", args); 682 String modeString = StringUtils.popOptionWithArgument("-mode", args); 683 Integer mode = (modeString == null) ? 684 null : Integer.parseInt(modeString, 8); 685 String limitString = StringUtils.popOptionWithArgument("-limit", args); 686 Long limit = AdminHelper.parseLimitString(limitString); 687 String maxTtlString = StringUtils.popOptionWithArgument("-maxTtl", args); 688 Long maxTtl; 689 try { 690 maxTtl = AdminHelper.parseTtlString(maxTtlString); 691 } catch (IOException e) { 692 System.err.println( 693 "Error while parsing maxTtl value: " + e.getMessage()); 694 return 1; 695 } 696 String name = StringUtils.popFirstNonOption(args); 697 if (name == null) { 698 System.err.println("You must specify a name when creating a " + 699 "cache pool."); 700 return 1; 701 } 702 if (!args.isEmpty()) { 703 System.err.print("Can't understand arguments: " + 704 Joiner.on(" ").join(args) + "\n"); 705 System.err.println("Usage is " + getShortUsage()); 706 return 1; 707 } 708 boolean changed = false; 709 CachePoolInfo info = new CachePoolInfo(name); 710 if (owner != null) { 711 info.setOwnerName(owner); 712 changed = true; 713 } 714 if (group != null) { 715 info.setGroupName(group); 716 changed = true; 717 } 718 if (mode != null) { 719 info.setMode(new FsPermission(mode.shortValue())); 720 changed = true; 721 } 722 if (limit != null) { 723 info.setLimit(limit); 724 changed = true; 725 } 726 if (maxTtl != null) { 727 info.setMaxRelativeExpiryMs(maxTtl); 728 changed = true; 729 } 730 if (!changed) { 731 System.err.println("You must specify at least one attribute to " + 732 "change in the cache pool."); 733 return 1; 734 } 735 DistributedFileSystem dfs = AdminHelper.getDFS(conf); 736 try { 737 dfs.modifyCachePool(info); 738 } catch (IOException e) { 739 System.err.println(AdminHelper.prettifyException(e)); 740 return 2; 741 } 742 System.out.print("Successfully modified cache pool " + name); 743 String prefix = " to have "; 744 if (owner != null) { 745 System.out.print(prefix + "owner name " + owner); 746 prefix = " and "; 747 } 748 if (group != null) { 749 System.out.print(prefix + "group name " + group); 750 prefix = " and "; 751 } 752 if (mode != null) { 753 System.out.print(prefix + "mode " + new FsPermission(mode.shortValue())); 754 prefix = " and "; 755 } 756 if (limit != null) { 757 System.out.print(prefix + "limit " + limit); 758 prefix = " and "; 759 } 760 if (maxTtl != null) { 761 System.out.print(prefix + "max time-to-live " + maxTtlString); 762 } 763 System.out.print("\n"); 764 return 0; 765 } 766 } 767 768 private static class RemoveCachePoolCommand implements AdminHelper.Command { 769 770 @Override getName()771 public String getName() { 772 return "-removePool"; 773 } 774 775 @Override getShortUsage()776 public String getShortUsage() { 777 return "[" + getName() + " <name>]\n"; 778 } 779 780 @Override getLongUsage()781 public String getLongUsage() { 782 return getShortUsage() + "\n" + 783 WordUtils.wrap("Remove a cache pool. This also uncaches paths " + 784 "associated with the pool.\n\n", AdminHelper.MAX_LINE_WIDTH) + 785 "<name> Name of the cache pool to remove.\n"; 786 } 787 788 @Override run(Configuration conf, List<String> args)789 public int run(Configuration conf, List<String> args) throws IOException { 790 String name = StringUtils.popFirstNonOption(args); 791 if (name == null) { 792 System.err.println("You must specify a name when deleting a " + 793 "cache pool."); 794 return 1; 795 } 796 if (!args.isEmpty()) { 797 System.err.print("Can't understand arguments: " + 798 Joiner.on(" ").join(args) + "\n"); 799 System.err.println("Usage is " + getShortUsage()); 800 return 1; 801 } 802 DistributedFileSystem dfs = AdminHelper.getDFS(conf); 803 try { 804 dfs.removeCachePool(name); 805 } catch (IOException e) { 806 System.err.println(AdminHelper.prettifyException(e)); 807 return 2; 808 } 809 System.out.println("Successfully removed cache pool " + name + "."); 810 return 0; 811 } 812 } 813 814 private static class ListCachePoolsCommand implements AdminHelper.Command { 815 816 @Override getName()817 public String getName() { 818 return "-listPools"; 819 } 820 821 @Override getShortUsage()822 public String getShortUsage() { 823 return "[" + getName() + " [-stats] [<name>]]\n"; 824 } 825 826 @Override getLongUsage()827 public String getLongUsage() { 828 TableListing listing = AdminHelper.getOptionDescriptionListing(); 829 listing.addRow("-stats", "Display additional cache pool statistics."); 830 listing.addRow("<name>", "If specified, list only the named cache pool."); 831 832 return getShortUsage() + "\n" + 833 WordUtils.wrap("Display information about one or more cache pools, " + 834 "e.g. name, owner, group, permissions, etc.", 835 AdminHelper.MAX_LINE_WIDTH) + "\n\n" + listing.toString(); 836 } 837 838 @Override run(Configuration conf, List<String> args)839 public int run(Configuration conf, List<String> args) throws IOException { 840 String name = StringUtils.popFirstNonOption(args); 841 final boolean printStats = StringUtils.popOption("-stats", args); 842 if (!args.isEmpty()) { 843 System.err.print("Can't understand arguments: " + 844 Joiner.on(" ").join(args) + "\n"); 845 System.err.println("Usage is " + getShortUsage()); 846 return 1; 847 } 848 DistributedFileSystem dfs = AdminHelper.getDFS(conf); 849 TableListing.Builder builder = new TableListing.Builder(). 850 addField("NAME", Justification.LEFT). 851 addField("OWNER", Justification.LEFT). 852 addField("GROUP", Justification.LEFT). 853 addField("MODE", Justification.LEFT). 854 addField("LIMIT", Justification.RIGHT). 855 addField("MAXTTL", Justification.RIGHT); 856 if (printStats) { 857 builder. 858 addField("BYTES_NEEDED", Justification.RIGHT). 859 addField("BYTES_CACHED", Justification.RIGHT). 860 addField("BYTES_OVERLIMIT", Justification.RIGHT). 861 addField("FILES_NEEDED", Justification.RIGHT). 862 addField("FILES_CACHED", Justification.RIGHT); 863 } 864 TableListing listing = builder.build(); 865 int numResults = 0; 866 try { 867 RemoteIterator<CachePoolEntry> iter = dfs.listCachePools(); 868 while (iter.hasNext()) { 869 CachePoolEntry entry = iter.next(); 870 CachePoolInfo info = entry.getInfo(); 871 LinkedList<String> row = new LinkedList<String>(); 872 if (name == null || info.getPoolName().equals(name)) { 873 row.add(info.getPoolName()); 874 row.add(info.getOwnerName()); 875 row.add(info.getGroupName()); 876 row.add(info.getMode() != null ? info.getMode().toString() : null); 877 Long limit = info.getLimit(); 878 String limitString; 879 if (limit != null && limit.equals(CachePoolInfo.LIMIT_UNLIMITED)) { 880 limitString = "unlimited"; 881 } else { 882 limitString = "" + limit; 883 } 884 row.add(limitString); 885 Long maxTtl = info.getMaxRelativeExpiryMs(); 886 String maxTtlString = null; 887 888 if (maxTtl != null) { 889 if (maxTtl == CachePoolInfo.RELATIVE_EXPIRY_NEVER) { 890 maxTtlString = "never"; 891 } else { 892 maxTtlString = DFSUtil.durationToString(maxTtl); 893 } 894 } 895 row.add(maxTtlString); 896 if (printStats) { 897 CachePoolStats stats = entry.getStats(); 898 row.add(Long.toString(stats.getBytesNeeded())); 899 row.add(Long.toString(stats.getBytesCached())); 900 row.add(Long.toString(stats.getBytesOverlimit())); 901 row.add(Long.toString(stats.getFilesNeeded())); 902 row.add(Long.toString(stats.getFilesCached())); 903 } 904 listing.addRow(row.toArray(new String[row.size()])); 905 ++numResults; 906 if (name != null) { 907 break; 908 } 909 } 910 } 911 } catch (IOException e) { 912 System.err.println(AdminHelper.prettifyException(e)); 913 return 2; 914 } 915 System.out.print(String.format("Found %d result%s.%n", numResults, 916 (numResults == 1 ? "" : "s"))); 917 if (numResults > 0) { 918 System.out.print(listing); 919 } 920 // If list pools succeed, we return 0 (success exit code) 921 return 0; 922 } 923 } 924 925 private static final AdminHelper.Command[] COMMANDS = { 926 new AddCacheDirectiveInfoCommand(), 927 new ModifyCacheDirectiveInfoCommand(), 928 new ListCacheDirectiveInfoCommand(), 929 new RemoveCacheDirectiveInfoCommand(), 930 new RemoveCacheDirectiveInfosCommand(), 931 new AddCachePoolCommand(), 932 new ModifyCachePoolCommand(), 933 new RemoveCachePoolCommand(), 934 new ListCachePoolsCommand() 935 }; 936 } 937