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