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