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 */ 018package org.apache.hadoop.hbase.regionserver; 019 020import java.util.List; 021import org.apache.hadoop.hbase.Cell; 022import org.apache.hadoop.hbase.HBaseInterfaceAudience; 023import org.apache.hadoop.hbase.client.metrics.ServerSideScanMetrics; 024import org.apache.hadoop.hbase.util.EnvironmentEdgeManager; 025import org.apache.yetus.audience.InterfaceAudience; 026import org.apache.yetus.audience.InterfaceStability; 027 028/** 029 * ScannerContext instances encapsulate limit tracking AND progress towards those limits during 030 * invocations of {@link InternalScanner#next(java.util.List)} and 031 * {@link RegionScanner#next(java.util.List)}. 032 * <p> 033 * A ScannerContext instance should be updated periodically throughout execution whenever progress 034 * towards a limit has been made. Each limit can be checked via the appropriate checkLimit method. 035 * <p> 036 * Once a limit has been reached, the scan will stop. The invoker of 037 * {@link InternalScanner#next(java.util.List)} or {@link RegionScanner#next(java.util.List)} can 038 * use the appropriate check*Limit methods to see exactly which limits have been reached. 039 * Alternatively, {@link #checkAnyLimitReached(LimitScope)} is provided to see if ANY limit was 040 * reached 041 * <p> 042 * {@link NoLimitScannerContext#NO_LIMIT} is an immutable static definition that can be used 043 * whenever a {@link ScannerContext} is needed but limits do not need to be enforced. 044 * <p> 045 * NOTE: It is important that this class only ever expose setter methods that can be safely skipped 046 * when limits should be NOT enforced. This is because of the necessary immutability of the class 047 * {@link NoLimitScannerContext}. If a setter cannot be safely skipped, the immutable nature of 048 * {@link NoLimitScannerContext} will lead to incorrect behavior. 049 */ 050@InterfaceAudience.LimitedPrivate(HBaseInterfaceAudience.COPROC) 051@InterfaceStability.Evolving 052public class ScannerContext { 053 054 LimitFields limits; 055 /** 056 * A different set of progress fields. Only include batch, dataSize and heapSize. Compare to 057 * LimitFields, ProgressFields doesn't contain time field. As we save a deadline in LimitFields, 058 * so use {@link EnvironmentEdgeManager#currentTime()} directly when check time limit. 059 */ 060 ProgressFields progress; 061 062 /** 063 * The state of the scanner after the invocation of {@link InternalScanner#next(java.util.List)} 064 * or {@link RegionScanner#next(java.util.List)}. 065 */ 066 NextState scannerState; 067 private static final NextState DEFAULT_STATE = NextState.MORE_VALUES; 068 069 /** 070 * Used as an indication to invocations of {@link InternalScanner#next(java.util.List)} and 071 * {@link RegionScanner#next(java.util.List)} that, if true, the progress tracked within this 072 * {@link ScannerContext} instance should be considered while evaluating the limits. Useful for 073 * enforcing a set of limits across multiple calls (i.e. the limit may not be reached in a single 074 * invocation, but any progress made should be considered in future invocations) 075 * <p> 076 * Defaulting this value to false means that, by default, any tracked progress will be wiped clean 077 * on invocations to {@link InternalScanner#next(java.util.List)} and 078 * {@link RegionScanner#next(java.util.List)} and the call will be treated as though no progress 079 * has been made towards the limits so far. 080 * <p> 081 * This is an important mechanism. Users of Internal/Region scanners expect that they can define 082 * some limits and then repeatedly invoke {@link InternalScanner#next(List)} or 083 * {@link RegionScanner#next(List)} where each invocation respects these limits separately. 084 * <p> 085 * For example: 086 * 087 * <pre> 088 * {@code 089 * ScannerContext context = new ScannerContext.newBuilder().setBatchLimit(5).build(); 090 * RegionScanner scanner = ... 091 * List<Cell> results = new ArrayList<Cell>(); 092 * while(scanner.next(results, context)) { 093 * // Do something with a batch of 5 cells 094 * } 095 * } 096 * </pre> 097 * 098 * However, in the case of RPCs, the server wants to be able to define a set of limits for a 099 * particular RPC request and have those limits respected across multiple invocations. This means 100 * that the progress made towards the limits in earlier calls will be saved and considered in 101 * future invocations 102 */ 103 boolean keepProgress; 104 private static boolean DEFAULT_KEEP_PROGRESS = false; 105 106 /** 107 * Allows temporarily ignoring limits and skipping tracking of batch and size progress. Used when 108 * skipping to the next row, in which case all processed cells are thrown away so should not count 109 * towards progress. 110 */ 111 boolean skippingRow = false; 112 113 private Cell lastPeekedCell = null; 114 115 // Set this to true will have the same behavior with reaching the time limit. 116 // This is used when you want to make the current RSRpcService.scan returns immediately. For 117 // example, when we want to switch from pread to stream, we can only do it after the rpc call is 118 // returned. 119 private boolean returnImmediately; 120 121 /** 122 * Tracks the relevant server side metrics during scans. null when metrics should not be tracked 123 */ 124 final ServerSideScanMetrics metrics; 125 126 ScannerContext(boolean keepProgress, LimitFields limitsToCopy, boolean trackMetrics) { 127 this.limits = new LimitFields(); 128 if (limitsToCopy != null) { 129 this.limits.copy(limitsToCopy); 130 } 131 132 // Progress fields are initialized to 0 133 progress = new ProgressFields(0, 0, 0, 0); 134 135 this.keepProgress = keepProgress; 136 this.scannerState = DEFAULT_STATE; 137 this.metrics = trackMetrics ? new ServerSideScanMetrics() : null; 138 } 139 140 public boolean isTrackingMetrics() { 141 return this.metrics != null; 142 } 143 144 /** 145 * Get the metrics instance. Should only be called after a call to {@link #isTrackingMetrics()} 146 * has been made to confirm that metrics are indeed being tracked. 147 * @return {@link ServerSideScanMetrics} instance that is tracking metrics for this scan 148 */ 149 public ServerSideScanMetrics getMetrics() { 150 assert isTrackingMetrics(); 151 return this.metrics; 152 } 153 154 /** 155 * @return true if the progress tracked so far in this instance will be considered during an 156 * invocation of {@link InternalScanner#next(java.util.List)} or 157 * {@link RegionScanner#next(java.util.List)}. false when the progress tracked so far 158 * should not be considered and should instead be wiped away via {@link #clearProgress()}. 159 * This only applies to per-row progress, like batch and data/heap size. Block size is 160 * never reset because it tracks all of the blocks scanned for an entire request. 161 */ 162 boolean getKeepProgress() { 163 return keepProgress; 164 } 165 166 void setKeepProgress(boolean keepProgress) { 167 this.keepProgress = keepProgress; 168 } 169 170 /** 171 * In this mode, only block size progress is tracked, and limits are ignored. We set this mode 172 * when skipping to next row, in which case all cells returned a thrown away so should not count 173 * towards progress. 174 * @return true if we are in skipping row mode. 175 */ 176 public boolean getSkippingRow() { 177 return skippingRow; 178 } 179 180 /** 181 * @param skippingRow set true to cause disabling of collecting per-cell progress or enforcing any 182 * limits. This is used when trying to skip over all cells in a row, in which 183 * case those cells are thrown away so should not count towards progress. 184 */ 185 void setSkippingRow(boolean skippingRow) { 186 this.skippingRow = skippingRow; 187 } 188 189 /** 190 * Progress towards the batch limit has been made. Increment internal tracking of batch progress 191 */ 192 void incrementBatchProgress(int batch) { 193 if (skippingRow) { 194 return; 195 } 196 int currentBatch = progress.getBatch(); 197 progress.setBatch(currentBatch + batch); 198 } 199 200 /** 201 * Progress towards the size limit has been made. Increment internal tracking of size progress 202 */ 203 void incrementSizeProgress(long dataSize, long heapSize) { 204 if (skippingRow) { 205 return; 206 } 207 long curDataSize = progress.getDataSize(); 208 progress.setDataSize(curDataSize + dataSize); 209 long curHeapSize = progress.getHeapSize(); 210 progress.setHeapSize(curHeapSize + heapSize); 211 } 212 213 /** 214 * Progress towards the block limit has been made. Increment internal track of block progress 215 */ 216 void incrementBlockProgress(int blockSize) { 217 if (blockSize > 0) { 218 long curBlockSize = progress.getBlockSize(); 219 progress.setBlockSize(curBlockSize + blockSize); 220 } 221 } 222 223 int getBatchProgress() { 224 return progress.getBatch(); 225 } 226 227 long getDataSizeProgress() { 228 return progress.getDataSize(); 229 } 230 231 long getHeapSizeProgress() { 232 return progress.getHeapSize(); 233 } 234 235 long getBlockSizeProgress() { 236 return progress.getBlockSize(); 237 } 238 239 void setProgress(int batchProgress, long sizeProgress, long heapSizeProgress) { 240 setBatchProgress(batchProgress); 241 setSizeProgress(sizeProgress, heapSizeProgress); 242 } 243 244 void setSizeProgress(long dataSizeProgress, long heapSizeProgress) { 245 progress.setDataSize(dataSizeProgress); 246 progress.setHeapSize(heapSizeProgress); 247 } 248 249 void setBatchProgress(int batchProgress) { 250 progress.setBatch(batchProgress); 251 } 252 253 /** 254 * Clear away any progress that has been made so far. All progress fields are reset to initial 255 * values. Only clears progress that should reset between rows. {@link #getBlockSizeProgress()} is 256 * not reset because it increments for all blocks scanned whether the result is included or 257 * filtered. 258 */ 259 void clearProgress() { 260 progress.setFields(0, 0, 0, getBlockSizeProgress()); 261 } 262 263 /** 264 * Note that this is not a typical setter. This setter returns the {@link NextState} that was 265 * passed in so that methods can be invoked against the new state. Furthermore, this pattern 266 * allows the {@link NoLimitScannerContext} to cleanly override this setter and simply return the 267 * new state, thus preserving the immutability of {@link NoLimitScannerContext} 268 * @return The state that was passed in. 269 */ 270 NextState setScannerState(NextState state) { 271 if (!NextState.isValidState(state)) { 272 throw new IllegalArgumentException("Cannot set to invalid state: " + state); 273 } 274 275 this.scannerState = state; 276 return state; 277 } 278 279 /** 280 * @return true when we have more cells for the current row. This usually because we have reached 281 * a limit in the middle of a row 282 */ 283 boolean mayHaveMoreCellsInRow() { 284 return scannerState == NextState.SIZE_LIMIT_REACHED_MID_ROW 285 || scannerState == NextState.TIME_LIMIT_REACHED_MID_ROW 286 || scannerState == NextState.BATCH_LIMIT_REACHED; 287 } 288 289 /** Returns true if the batch limit can be enforced in the checker's scope */ 290 boolean hasBatchLimit(LimitScope checkerScope) { 291 return limits.canEnforceBatchLimitFromScope(checkerScope) && limits.getBatch() > 0; 292 } 293 294 /** Returns true if the size limit can be enforced in the checker's scope */ 295 boolean hasSizeLimit(LimitScope checkerScope) { 296 return limits.canEnforceSizeLimitFromScope(checkerScope) 297 && (limits.getDataSize() > 0 || limits.getHeapSize() > 0 || limits.getBlockSize() > 0); 298 } 299 300 /** Returns true if the time limit can be enforced in the checker's scope */ 301 boolean hasTimeLimit(LimitScope checkerScope) { 302 return limits.canEnforceTimeLimitFromScope(checkerScope) 303 && (limits.getTime() > 0 || returnImmediately); 304 } 305 306 /** Returns true if any limit can be enforced within the checker's scope */ 307 boolean hasAnyLimit(LimitScope checkerScope) { 308 return hasBatchLimit(checkerScope) || hasSizeLimit(checkerScope) || hasTimeLimit(checkerScope); 309 } 310 311 /** 312 * @param scope The scope in which the size limit will be enforced 313 */ 314 void setSizeLimitScope(LimitScope scope) { 315 limits.setSizeScope(scope); 316 } 317 318 /** 319 * @param scope The scope in which the time limit will be enforced 320 */ 321 void setTimeLimitScope(LimitScope scope) { 322 limits.setTimeScope(scope); 323 } 324 325 int getBatchLimit() { 326 return limits.getBatch(); 327 } 328 329 long getDataSizeLimit() { 330 return limits.getDataSize(); 331 } 332 333 long getTimeLimit() { 334 return limits.getTime(); 335 } 336 337 /** 338 * @param checkerScope The scope that the limit is being checked from 339 * @return true when the limit is enforceable from the checker's scope and it has been reached 340 */ 341 boolean checkBatchLimit(LimitScope checkerScope) { 342 return !skippingRow && hasBatchLimit(checkerScope) && progress.getBatch() >= limits.getBatch(); 343 } 344 345 /** 346 * @param checkerScope The scope that the limit is being checked from 347 * @return true when the limit is enforceable from the checker's scope and it has been reached 348 */ 349 boolean checkSizeLimit(LimitScope checkerScope) { 350 return !skippingRow && hasSizeLimit(checkerScope) 351 && (progress.getDataSize() >= limits.getDataSize() 352 || progress.getHeapSize() >= limits.getHeapSize() 353 || progress.getBlockSize() >= limits.getBlockSize()); 354 } 355 356 /** 357 * @param checkerScope The scope that the limit is being checked from. The time limit is always 358 * checked against {@link EnvironmentEdgeManager.currentTime} 359 * @return true when the limit is enforceable from the checker's scope and it has been reached 360 */ 361 boolean checkTimeLimit(LimitScope checkerScope) { 362 return !skippingRow && hasTimeLimit(checkerScope) 363 && (returnImmediately || EnvironmentEdgeManager.currentTime() >= limits.getTime()); 364 } 365 366 /** 367 * @param checkerScope The scope that the limits are being checked from 368 * @return true when some limit is enforceable from the checker's scope and it has been reached 369 */ 370 boolean checkAnyLimitReached(LimitScope checkerScope) { 371 return checkSizeLimit(checkerScope) || checkBatchLimit(checkerScope) 372 || checkTimeLimit(checkerScope); 373 } 374 375 Cell getLastPeekedCell() { 376 return lastPeekedCell; 377 } 378 379 void setLastPeekedCell(Cell lastPeekedCell) { 380 this.lastPeekedCell = lastPeekedCell; 381 } 382 383 void returnImmediately() { 384 this.returnImmediately = true; 385 } 386 387 @Override 388 public String toString() { 389 StringBuilder sb = new StringBuilder(); 390 sb.append("{"); 391 392 sb.append("limits:"); 393 sb.append(limits); 394 395 sb.append(", progress:"); 396 sb.append(progress); 397 398 sb.append(", keepProgress:"); 399 sb.append(keepProgress); 400 401 sb.append(", state:"); 402 sb.append(scannerState); 403 404 sb.append("}"); 405 return sb.toString(); 406 } 407 408 public static Builder newBuilder() { 409 return new Builder(); 410 } 411 412 public static Builder newBuilder(boolean keepProgress) { 413 return new Builder(keepProgress); 414 } 415 416 public static final class Builder { 417 boolean keepProgress = DEFAULT_KEEP_PROGRESS; 418 boolean trackMetrics = false; 419 LimitFields limits = new LimitFields(); 420 421 private Builder() { 422 } 423 424 private Builder(boolean keepProgress) { 425 this.keepProgress = keepProgress; 426 } 427 428 public Builder setKeepProgress(boolean keepProgress) { 429 this.keepProgress = keepProgress; 430 return this; 431 } 432 433 public Builder setTrackMetrics(boolean trackMetrics) { 434 this.trackMetrics = trackMetrics; 435 return this; 436 } 437 438 public Builder setSizeLimit(LimitScope sizeScope, long dataSizeLimit, long heapSizeLimit, 439 long blockSizeLimit) { 440 limits.setDataSize(dataSizeLimit); 441 limits.setHeapSize(heapSizeLimit); 442 limits.setSizeScope(sizeScope); 443 limits.setBlockSize(blockSizeLimit); 444 return this; 445 } 446 447 public Builder setTimeLimit(LimitScope timeScope, long timeLimit) { 448 limits.setTime(timeLimit); 449 limits.setTimeScope(timeScope); 450 return this; 451 } 452 453 public Builder setBatchLimit(int batchLimit) { 454 limits.setBatch(batchLimit); 455 return this; 456 } 457 458 public ScannerContext build() { 459 return new ScannerContext(keepProgress, limits, trackMetrics); 460 } 461 } 462 463 /** 464 * The possible states a scanner may be in following a call to {@link InternalScanner#next(List)} 465 */ 466 public enum NextState { 467 MORE_VALUES(true, false), 468 NO_MORE_VALUES(false, false), 469 SIZE_LIMIT_REACHED(true, true), 470 471 /** 472 * Special case of size limit reached to indicate that the size limit was reached in the middle 473 * of a row and thus a partial results was formed 474 */ 475 SIZE_LIMIT_REACHED_MID_ROW(true, true), 476 TIME_LIMIT_REACHED(true, true), 477 478 /** 479 * Special case of time limit reached to indicate that the time limit was reached in the middle 480 * of a row and thus a partial results was formed 481 */ 482 TIME_LIMIT_REACHED_MID_ROW(true, true), 483 BATCH_LIMIT_REACHED(true, true); 484 485 private final boolean moreValues; 486 private final boolean limitReached; 487 488 private NextState(boolean moreValues, boolean limitReached) { 489 this.moreValues = moreValues; 490 this.limitReached = limitReached; 491 } 492 493 /** 494 * @return true when the state indicates that more values may follow those that have been 495 * returned 496 */ 497 public boolean hasMoreValues() { 498 return this.moreValues; 499 } 500 501 /** Returns true when the state indicates that a limit has been reached and scan should stop */ 502 public boolean limitReached() { 503 return this.limitReached; 504 } 505 506 public static boolean isValidState(NextState state) { 507 return state != null; 508 } 509 510 public static boolean hasMoreValues(NextState state) { 511 return isValidState(state) && state.hasMoreValues(); 512 } 513 } 514 515 /** 516 * The various scopes where a limit can be enforced. Used to differentiate when a limit should be 517 * enforced or not. 518 */ 519 public enum LimitScope { 520 /** 521 * Enforcing a limit between rows means that the limit will not be considered until all the 522 * cells for a particular row have been retrieved 523 */ 524 BETWEEN_ROWS(0), 525 526 /** 527 * Enforcing a limit between cells means that the limit will be considered after each full cell 528 * has been retrieved 529 */ 530 BETWEEN_CELLS(1); 531 532 /** 533 * When enforcing a limit, we must check that the scope is appropriate for enforcement. 534 * <p> 535 * To communicate this concept, each scope has a depth. A limit will be enforced if the depth of 536 * the checker's scope is less than or equal to the limit's scope. This means that when checking 537 * limits, the checker must know their own scope (i.e. are they checking the limits between 538 * rows, between cells, etc...) 539 */ 540 final int depth; 541 542 LimitScope(int depth) { 543 this.depth = depth; 544 } 545 546 final int depth() { 547 return depth; 548 } 549 550 /** 551 * @param checkerScope The scope in which the limit is being checked 552 * @return true when the checker is in a scope that indicates the limit can be enforced. Limits 553 * can be enforced from "higher or equal" scopes (i.e. the checker's scope is at a 554 * lesser depth than the limit) 555 */ 556 boolean canEnforceLimitFromScope(LimitScope checkerScope) { 557 return checkerScope != null && checkerScope.depth() <= depth; 558 } 559 } 560 561 /** 562 * The different fields that can be used as limits in calls to 563 * {@link InternalScanner#next(java.util.List)} and {@link RegionScanner#next(java.util.List)} 564 */ 565 private static class LimitFields { 566 /** 567 * Default values of the limit fields. Defined such that if a field does NOT change from its 568 * default, it will not be enforced 569 */ 570 private static int DEFAULT_BATCH = -1; 571 private static long DEFAULT_SIZE = -1L; 572 private static long DEFAULT_TIME = -1L; 573 574 /** 575 * Default scope that is assigned to a limit if a scope is not specified. 576 */ 577 private static final LimitScope DEFAULT_SCOPE = LimitScope.BETWEEN_ROWS; 578 579 // The batch limit will always be enforced between cells, thus, there isn't a field to hold the 580 // batch scope 581 int batch = DEFAULT_BATCH; 582 583 LimitScope sizeScope = DEFAULT_SCOPE; 584 // The sum of cell data sizes(key + value). The Cell data might be in on heap or off heap area. 585 long dataSize = DEFAULT_SIZE; 586 // The sum of heap space occupied by all tracked cells. This includes Cell POJO's overhead as 587 // such AND data cells of Cells which are in on heap area. 588 long heapSize = DEFAULT_SIZE; 589 // The total amount of block bytes that have been loaded in order to process cells for the 590 // request. 591 long blockSize = DEFAULT_SIZE; 592 593 LimitScope timeScope = DEFAULT_SCOPE; 594 long time = DEFAULT_TIME; 595 596 /** 597 * Fields keep their default values. 598 */ 599 LimitFields() { 600 } 601 602 void copy(LimitFields limitsToCopy) { 603 if (limitsToCopy != null) { 604 setFields(limitsToCopy.getBatch(), limitsToCopy.getSizeScope(), limitsToCopy.getDataSize(), 605 limitsToCopy.getHeapSize(), limitsToCopy.getBlockSize(), limitsToCopy.getTimeScope(), 606 limitsToCopy.getTime()); 607 } 608 } 609 610 /** 611 * Set all fields together. 612 */ 613 void setFields(int batch, LimitScope sizeScope, long dataSize, long heapSize, long blockSize, 614 LimitScope timeScope, long time) { 615 setBatch(batch); 616 setSizeScope(sizeScope); 617 setDataSize(dataSize); 618 setHeapSize(heapSize); 619 setBlockSize(blockSize); 620 setTimeScope(timeScope); 621 setTime(time); 622 } 623 624 int getBatch() { 625 return this.batch; 626 } 627 628 void setBatch(int batch) { 629 this.batch = batch; 630 } 631 632 /** Returns true when the limit can be enforced from the scope of the checker */ 633 boolean canEnforceBatchLimitFromScope(LimitScope checkerScope) { 634 return LimitScope.BETWEEN_CELLS.canEnforceLimitFromScope(checkerScope); 635 } 636 637 long getDataSize() { 638 return this.dataSize; 639 } 640 641 long getHeapSize() { 642 return this.heapSize; 643 } 644 645 long getBlockSize() { 646 return this.blockSize; 647 } 648 649 void setDataSize(long dataSize) { 650 this.dataSize = dataSize; 651 } 652 653 void setHeapSize(long heapSize) { 654 this.heapSize = heapSize; 655 } 656 657 void setBlockSize(long blockSize) { 658 this.blockSize = blockSize; 659 } 660 661 /** Returns {@link LimitScope} indicating scope in which the size limit is enforced */ 662 LimitScope getSizeScope() { 663 return this.sizeScope; 664 } 665 666 /** 667 * Change the scope in which the size limit is enforced 668 */ 669 void setSizeScope(LimitScope scope) { 670 this.sizeScope = scope; 671 } 672 673 /** Returns true when the limit can be enforced from the scope of the checker */ 674 boolean canEnforceSizeLimitFromScope(LimitScope checkerScope) { 675 return this.sizeScope.canEnforceLimitFromScope(checkerScope); 676 } 677 678 long getTime() { 679 return this.time; 680 } 681 682 void setTime(long time) { 683 this.time = time; 684 } 685 686 /** Returns {@link LimitScope} indicating scope in which the time limit is enforced */ 687 LimitScope getTimeScope() { 688 return this.timeScope; 689 } 690 691 /** 692 * Change the scope in which the time limit is enforced 693 */ 694 void setTimeScope(LimitScope scope) { 695 this.timeScope = scope; 696 } 697 698 /** Returns true when the limit can be enforced from the scope of the checker */ 699 boolean canEnforceTimeLimitFromScope(LimitScope checkerScope) { 700 return this.timeScope.canEnforceLimitFromScope(checkerScope); 701 } 702 703 @Override 704 public String toString() { 705 StringBuilder sb = new StringBuilder(); 706 sb.append("{"); 707 708 sb.append("batch:"); 709 sb.append(batch); 710 711 sb.append(", dataSize:"); 712 sb.append(dataSize); 713 714 sb.append(", heapSize:"); 715 sb.append(heapSize); 716 717 sb.append(", blockSize:"); 718 sb.append(blockSize); 719 720 sb.append(", sizeScope:"); 721 sb.append(sizeScope); 722 723 sb.append(", time:"); 724 sb.append(time); 725 726 sb.append(", timeScope:"); 727 sb.append(timeScope); 728 729 sb.append("}"); 730 return sb.toString(); 731 } 732 } 733 734 private static class ProgressFields { 735 736 private static int DEFAULT_BATCH = -1; 737 private static long DEFAULT_SIZE = -1L; 738 739 // The batch limit will always be enforced between cells, thus, there isn't a field to hold the 740 // batch scope 741 int batch = DEFAULT_BATCH; 742 743 // The sum of cell data sizes(key + value). The Cell data might be in on heap or off heap area. 744 long dataSize = DEFAULT_SIZE; 745 // The sum of heap space occupied by all tracked cells. This includes Cell POJO's overhead as 746 // such AND data cells of Cells which are in on heap area. 747 long heapSize = DEFAULT_SIZE; 748 // The total amount of block bytes that have been loaded in order to process cells for the 749 // request. 750 long blockSize = DEFAULT_SIZE; 751 752 ProgressFields(int batch, long size, long heapSize, long blockSize) { 753 setFields(batch, size, heapSize, blockSize); 754 } 755 756 /** 757 * Set all fields together. 758 */ 759 void setFields(int batch, long dataSize, long heapSize, long blockSize) { 760 setBatch(batch); 761 setDataSize(dataSize); 762 setHeapSize(heapSize); 763 setBlockSize(blockSize); 764 } 765 766 int getBatch() { 767 return this.batch; 768 } 769 770 void setBatch(int batch) { 771 this.batch = batch; 772 } 773 774 long getDataSize() { 775 return this.dataSize; 776 } 777 778 long getHeapSize() { 779 return this.heapSize; 780 } 781 782 long getBlockSize() { 783 return this.blockSize; 784 } 785 786 void setDataSize(long dataSize) { 787 this.dataSize = dataSize; 788 } 789 790 void setBlockSize(long blockSize) { 791 this.blockSize = blockSize; 792 } 793 794 void setHeapSize(long heapSize) { 795 this.heapSize = heapSize; 796 } 797 798 @Override 799 public String toString() { 800 StringBuilder sb = new StringBuilder(); 801 sb.append("{"); 802 803 sb.append("batch:"); 804 sb.append(batch); 805 806 sb.append(", dataSize:"); 807 sb.append(dataSize); 808 809 sb.append(", heapSize:"); 810 sb.append(heapSize); 811 812 sb.append(", blockSize:"); 813 sb.append(blockSize); 814 815 sb.append("}"); 816 return sb.toString(); 817 } 818 } 819}