You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hbase.apache.org by mi...@apache.org on 2015/12/30 23:15:41 UTC

[20/51] [partial] hbase-site git commit: Published site at 07b623670647686084f8f5fd2038e2bafcfdac54.

http://git-wip-us.apache.org/repos/asf/hbase-site/blob/e5c3dcd1/devapidocs/src-html/org/apache/hadoop/hbase/regionserver/RSRpcServices.RegionScannerCloseCallBack.html
----------------------------------------------------------------------
diff --git a/devapidocs/src-html/org/apache/hadoop/hbase/regionserver/RSRpcServices.RegionScannerCloseCallBack.html b/devapidocs/src-html/org/apache/hadoop/hbase/regionserver/RSRpcServices.RegionScannerCloseCallBack.html
index be615ae..9d47569 100644
--- a/devapidocs/src-html/org/apache/hadoop/hbase/regionserver/RSRpcServices.RegionScannerCloseCallBack.html
+++ b/devapidocs/src-html/org/apache/hadoop/hbase/regionserver/RSRpcServices.RegionScannerCloseCallBack.html
@@ -2526,324 +2526,327 @@
 <span class="sourceLineNo">2518</span>      }<a name="line.2518"></a>
 <span class="sourceLineNo">2519</span>      assert scanner != null;<a name="line.2519"></a>
 <span class="sourceLineNo">2520</span>      if (request.hasRenew() &amp;&amp; request.getRenew()) {<a name="line.2520"></a>
-<span class="sourceLineNo">2521</span>        lease = regionServer.leases.removeLease(scannerName);<a name="line.2521"></a>
-<span class="sourceLineNo">2522</span>        if (lease != null &amp;&amp; scanners.containsKey(scannerName)) {<a name="line.2522"></a>
-<span class="sourceLineNo">2523</span>          regionServer.leases.addLease(lease);<a name="line.2523"></a>
-<span class="sourceLineNo">2524</span>        }<a name="line.2524"></a>
-<span class="sourceLineNo">2525</span>        return builder.build();<a name="line.2525"></a>
-<span class="sourceLineNo">2526</span>      }<a name="line.2526"></a>
-<span class="sourceLineNo">2527</span>      RpcCallContext context = RpcServer.getCurrentCall();<a name="line.2527"></a>
-<span class="sourceLineNo">2528</span>      Object lastBlock = null;<a name="line.2528"></a>
-<span class="sourceLineNo">2529</span><a name="line.2529"></a>
-<span class="sourceLineNo">2530</span>      quota = getQuotaManager().checkQuota(region, OperationQuota.OperationType.SCAN);<a name="line.2530"></a>
-<span class="sourceLineNo">2531</span>      long maxQuotaResultSize = Math.min(maxScannerResultSize, quota.getReadAvailable());<a name="line.2531"></a>
+<span class="sourceLineNo">2521</span>        rsh = scanners.get(scannerName);<a name="line.2521"></a>
+<span class="sourceLineNo">2522</span>        lease = regionServer.leases.removeLease(scannerName);<a name="line.2522"></a>
+<span class="sourceLineNo">2523</span>        if (lease != null &amp;&amp; rsh != null) {<a name="line.2523"></a>
+<span class="sourceLineNo">2524</span>          regionServer.leases.addLease(lease);<a name="line.2524"></a>
+<span class="sourceLineNo">2525</span>          // Increment the nextCallSeq value which is the next expected from client.<a name="line.2525"></a>
+<span class="sourceLineNo">2526</span>          rsh.incNextCallSeq();<a name="line.2526"></a>
+<span class="sourceLineNo">2527</span>        }<a name="line.2527"></a>
+<span class="sourceLineNo">2528</span>        return builder.build();<a name="line.2528"></a>
+<span class="sourceLineNo">2529</span>      }<a name="line.2529"></a>
+<span class="sourceLineNo">2530</span>      RpcCallContext context = RpcServer.getCurrentCall();<a name="line.2530"></a>
+<span class="sourceLineNo">2531</span>      Object lastBlock = null;<a name="line.2531"></a>
 <span class="sourceLineNo">2532</span><a name="line.2532"></a>
-<span class="sourceLineNo">2533</span>      if (rows &gt; 0) {<a name="line.2533"></a>
-<span class="sourceLineNo">2534</span>        // if nextCallSeq does not match throw Exception straight away. This needs to be<a name="line.2534"></a>
-<span class="sourceLineNo">2535</span>        // performed even before checking of Lease.<a name="line.2535"></a>
-<span class="sourceLineNo">2536</span>        // See HBASE-5974<a name="line.2536"></a>
-<span class="sourceLineNo">2537</span>        if (request.hasNextCallSeq()) {<a name="line.2537"></a>
-<span class="sourceLineNo">2538</span>          if (rsh != null) {<a name="line.2538"></a>
-<span class="sourceLineNo">2539</span>            if (request.getNextCallSeq() != rsh.getNextCallSeq()) {<a name="line.2539"></a>
-<span class="sourceLineNo">2540</span>              throw new OutOfOrderScannerNextException(<a name="line.2540"></a>
-<span class="sourceLineNo">2541</span>                "Expected nextCallSeq: " + rsh.getNextCallSeq()<a name="line.2541"></a>
-<span class="sourceLineNo">2542</span>                + " But the nextCallSeq got from client: " + request.getNextCallSeq() +<a name="line.2542"></a>
-<span class="sourceLineNo">2543</span>                "; request=" + TextFormat.shortDebugString(request));<a name="line.2543"></a>
-<span class="sourceLineNo">2544</span>            }<a name="line.2544"></a>
-<span class="sourceLineNo">2545</span>            // Increment the nextCallSeq value which is the next expected from client.<a name="line.2545"></a>
-<span class="sourceLineNo">2546</span>            rsh.incNextCallSeq();<a name="line.2546"></a>
-<span class="sourceLineNo">2547</span>          }<a name="line.2547"></a>
-<span class="sourceLineNo">2548</span>        }<a name="line.2548"></a>
-<span class="sourceLineNo">2549</span>        try {<a name="line.2549"></a>
-<span class="sourceLineNo">2550</span>          // Remove lease while its being processed in server; protects against case<a name="line.2550"></a>
-<span class="sourceLineNo">2551</span>          // where processing of request takes &gt; lease expiration time.<a name="line.2551"></a>
-<span class="sourceLineNo">2552</span>          lease = regionServer.leases.removeLease(scannerName);<a name="line.2552"></a>
-<span class="sourceLineNo">2553</span>          List&lt;Result&gt; results = new ArrayList&lt;Result&gt;();<a name="line.2553"></a>
-<span class="sourceLineNo">2554</span><a name="line.2554"></a>
-<span class="sourceLineNo">2555</span>          boolean done = false;<a name="line.2555"></a>
-<span class="sourceLineNo">2556</span>          // Call coprocessor. Get region info from scanner.<a name="line.2556"></a>
-<span class="sourceLineNo">2557</span>          if (region != null &amp;&amp; region.getCoprocessorHost() != null) {<a name="line.2557"></a>
-<span class="sourceLineNo">2558</span>            Boolean bypass = region.getCoprocessorHost().preScannerNext(<a name="line.2558"></a>
-<span class="sourceLineNo">2559</span>              scanner, results, rows);<a name="line.2559"></a>
-<span class="sourceLineNo">2560</span>            if (!results.isEmpty()) {<a name="line.2560"></a>
-<span class="sourceLineNo">2561</span>              for (Result r : results) {<a name="line.2561"></a>
-<span class="sourceLineNo">2562</span>                lastBlock = addSize(context, r, lastBlock);<a name="line.2562"></a>
-<span class="sourceLineNo">2563</span>              }<a name="line.2563"></a>
-<span class="sourceLineNo">2564</span>            }<a name="line.2564"></a>
-<span class="sourceLineNo">2565</span>            if (bypass != null &amp;&amp; bypass.booleanValue()) {<a name="line.2565"></a>
-<span class="sourceLineNo">2566</span>              done = true;<a name="line.2566"></a>
+<span class="sourceLineNo">2533</span>      quota = getQuotaManager().checkQuota(region, OperationQuota.OperationType.SCAN);<a name="line.2533"></a>
+<span class="sourceLineNo">2534</span>      long maxQuotaResultSize = Math.min(maxScannerResultSize, quota.getReadAvailable());<a name="line.2534"></a>
+<span class="sourceLineNo">2535</span><a name="line.2535"></a>
+<span class="sourceLineNo">2536</span>      if (rows &gt; 0) {<a name="line.2536"></a>
+<span class="sourceLineNo">2537</span>        // if nextCallSeq does not match throw Exception straight away. This needs to be<a name="line.2537"></a>
+<span class="sourceLineNo">2538</span>        // performed even before checking of Lease.<a name="line.2538"></a>
+<span class="sourceLineNo">2539</span>        // See HBASE-5974<a name="line.2539"></a>
+<span class="sourceLineNo">2540</span>        if (request.hasNextCallSeq()) {<a name="line.2540"></a>
+<span class="sourceLineNo">2541</span>          if (rsh != null) {<a name="line.2541"></a>
+<span class="sourceLineNo">2542</span>            if (request.getNextCallSeq() != rsh.getNextCallSeq()) {<a name="line.2542"></a>
+<span class="sourceLineNo">2543</span>              throw new OutOfOrderScannerNextException(<a name="line.2543"></a>
+<span class="sourceLineNo">2544</span>                "Expected nextCallSeq: " + rsh.getNextCallSeq()<a name="line.2544"></a>
+<span class="sourceLineNo">2545</span>                + " But the nextCallSeq got from client: " + request.getNextCallSeq() +<a name="line.2545"></a>
+<span class="sourceLineNo">2546</span>                "; request=" + TextFormat.shortDebugString(request));<a name="line.2546"></a>
+<span class="sourceLineNo">2547</span>            }<a name="line.2547"></a>
+<span class="sourceLineNo">2548</span>            // Increment the nextCallSeq value which is the next expected from client.<a name="line.2548"></a>
+<span class="sourceLineNo">2549</span>            rsh.incNextCallSeq();<a name="line.2549"></a>
+<span class="sourceLineNo">2550</span>          }<a name="line.2550"></a>
+<span class="sourceLineNo">2551</span>        }<a name="line.2551"></a>
+<span class="sourceLineNo">2552</span>        try {<a name="line.2552"></a>
+<span class="sourceLineNo">2553</span>          // Remove lease while its being processed in server; protects against case<a name="line.2553"></a>
+<span class="sourceLineNo">2554</span>          // where processing of request takes &gt; lease expiration time.<a name="line.2554"></a>
+<span class="sourceLineNo">2555</span>          lease = regionServer.leases.removeLease(scannerName);<a name="line.2555"></a>
+<span class="sourceLineNo">2556</span>          List&lt;Result&gt; results = new ArrayList&lt;Result&gt;();<a name="line.2556"></a>
+<span class="sourceLineNo">2557</span><a name="line.2557"></a>
+<span class="sourceLineNo">2558</span>          boolean done = false;<a name="line.2558"></a>
+<span class="sourceLineNo">2559</span>          // Call coprocessor. Get region info from scanner.<a name="line.2559"></a>
+<span class="sourceLineNo">2560</span>          if (region != null &amp;&amp; region.getCoprocessorHost() != null) {<a name="line.2560"></a>
+<span class="sourceLineNo">2561</span>            Boolean bypass = region.getCoprocessorHost().preScannerNext(<a name="line.2561"></a>
+<span class="sourceLineNo">2562</span>              scanner, results, rows);<a name="line.2562"></a>
+<span class="sourceLineNo">2563</span>            if (!results.isEmpty()) {<a name="line.2563"></a>
+<span class="sourceLineNo">2564</span>              for (Result r : results) {<a name="line.2564"></a>
+<span class="sourceLineNo">2565</span>                lastBlock = addSize(context, r, lastBlock);<a name="line.2565"></a>
+<span class="sourceLineNo">2566</span>              }<a name="line.2566"></a>
 <span class="sourceLineNo">2567</span>            }<a name="line.2567"></a>
-<span class="sourceLineNo">2568</span>          }<a name="line.2568"></a>
-<span class="sourceLineNo">2569</span><a name="line.2569"></a>
-<span class="sourceLineNo">2570</span>          if (!done) {<a name="line.2570"></a>
-<span class="sourceLineNo">2571</span>            long maxResultSize = Math.min(scanner.getMaxResultSize(), maxQuotaResultSize);<a name="line.2571"></a>
-<span class="sourceLineNo">2572</span>            if (maxResultSize &lt;= 0) {<a name="line.2572"></a>
-<span class="sourceLineNo">2573</span>              maxResultSize = maxQuotaResultSize;<a name="line.2573"></a>
-<span class="sourceLineNo">2574</span>            }<a name="line.2574"></a>
-<span class="sourceLineNo">2575</span>            // This is cells inside a row. Default size is 10 so if many versions or many cfs,<a name="line.2575"></a>
-<span class="sourceLineNo">2576</span>            // then we'll resize. Resizings show in profiler. Set it higher than 10. For now<a name="line.2576"></a>
-<span class="sourceLineNo">2577</span>            // arbitrary 32. TODO: keep record of general size of results being returned.<a name="line.2577"></a>
-<span class="sourceLineNo">2578</span>            List&lt;Cell&gt; values = new ArrayList&lt;Cell&gt;(32);<a name="line.2578"></a>
-<span class="sourceLineNo">2579</span>            region.startRegionOperation(Operation.SCAN);<a name="line.2579"></a>
-<span class="sourceLineNo">2580</span>            try {<a name="line.2580"></a>
-<span class="sourceLineNo">2581</span>              int i = 0;<a name="line.2581"></a>
-<span class="sourceLineNo">2582</span>              synchronized(scanner) {<a name="line.2582"></a>
-<span class="sourceLineNo">2583</span>                boolean stale = (region.getRegionInfo().getReplicaId() != 0);<a name="line.2583"></a>
-<span class="sourceLineNo">2584</span>                boolean clientHandlesPartials =<a name="line.2584"></a>
-<span class="sourceLineNo">2585</span>                    request.hasClientHandlesPartials() &amp;&amp; request.getClientHandlesPartials();<a name="line.2585"></a>
-<span class="sourceLineNo">2586</span>                boolean clientHandlesHeartbeats =<a name="line.2586"></a>
-<span class="sourceLineNo">2587</span>                    request.hasClientHandlesHeartbeats() &amp;&amp; request.getClientHandlesHeartbeats();<a name="line.2587"></a>
-<span class="sourceLineNo">2588</span><a name="line.2588"></a>
-<span class="sourceLineNo">2589</span>                // On the server side we must ensure that the correct ordering of partial results is<a name="line.2589"></a>
-<span class="sourceLineNo">2590</span>                // returned to the client to allow them to properly reconstruct the partial results.<a name="line.2590"></a>
-<span class="sourceLineNo">2591</span>                // If the coprocessor host is adding to the result list, we cannot guarantee the<a name="line.2591"></a>
-<span class="sourceLineNo">2592</span>                // correct ordering of partial results and so we prevent partial results from being<a name="line.2592"></a>
-<span class="sourceLineNo">2593</span>                // formed.<a name="line.2593"></a>
-<span class="sourceLineNo">2594</span>                boolean serverGuaranteesOrderOfPartials = results.isEmpty();<a name="line.2594"></a>
-<span class="sourceLineNo">2595</span>                boolean allowPartialResults =<a name="line.2595"></a>
-<span class="sourceLineNo">2596</span>                    clientHandlesPartials &amp;&amp; serverGuaranteesOrderOfPartials &amp;&amp; !isSmallScan;<a name="line.2596"></a>
-<span class="sourceLineNo">2597</span>                boolean moreRows = false;<a name="line.2597"></a>
-<span class="sourceLineNo">2598</span><a name="line.2598"></a>
-<span class="sourceLineNo">2599</span>                // Heartbeat messages occur when the processing of the ScanRequest is exceeds a<a name="line.2599"></a>
-<span class="sourceLineNo">2600</span>                // certain time threshold on the server. When the time threshold is exceeded, the<a name="line.2600"></a>
-<span class="sourceLineNo">2601</span>                // server stops the scan and sends back whatever Results it has accumulated within<a name="line.2601"></a>
-<span class="sourceLineNo">2602</span>                // that time period (may be empty). Since heartbeat messages have the potential to<a name="line.2602"></a>
-<span class="sourceLineNo">2603</span>                // create partial Results (in the event that the timeout occurs in the middle of a<a name="line.2603"></a>
-<span class="sourceLineNo">2604</span>                // row), we must only generate heartbeat messages when the client can handle both<a name="line.2604"></a>
-<span class="sourceLineNo">2605</span>                // heartbeats AND partials<a name="line.2605"></a>
-<span class="sourceLineNo">2606</span>                boolean allowHeartbeatMessages = clientHandlesHeartbeats &amp;&amp; allowPartialResults;<a name="line.2606"></a>
-<span class="sourceLineNo">2607</span><a name="line.2607"></a>
-<span class="sourceLineNo">2608</span>                // Default value of timeLimit is negative to indicate no timeLimit should be<a name="line.2608"></a>
-<span class="sourceLineNo">2609</span>                // enforced.<a name="line.2609"></a>
-<span class="sourceLineNo">2610</span>                long timeLimit = -1;<a name="line.2610"></a>
-<span class="sourceLineNo">2611</span><a name="line.2611"></a>
-<span class="sourceLineNo">2612</span>                // Set the time limit to be half of the more restrictive timeout value (one of the<a name="line.2612"></a>
-<span class="sourceLineNo">2613</span>                // timeout values must be positive). In the event that both values are positive, the<a name="line.2613"></a>
-<span class="sourceLineNo">2614</span>                // more restrictive of the two is used to calculate the limit.<a name="line.2614"></a>
-<span class="sourceLineNo">2615</span>                if (allowHeartbeatMessages &amp;&amp; (scannerLeaseTimeoutPeriod &gt; 0 || rpcTimeout &gt; 0)) {<a name="line.2615"></a>
-<span class="sourceLineNo">2616</span>                  long timeLimitDelta;<a name="line.2616"></a>
-<span class="sourceLineNo">2617</span>                  if (scannerLeaseTimeoutPeriod &gt; 0 &amp;&amp; rpcTimeout &gt; 0) {<a name="line.2617"></a>
-<span class="sourceLineNo">2618</span>                    timeLimitDelta = Math.min(scannerLeaseTimeoutPeriod, rpcTimeout);<a name="line.2618"></a>
-<span class="sourceLineNo">2619</span>                  } else {<a name="line.2619"></a>
-<span class="sourceLineNo">2620</span>                    timeLimitDelta =<a name="line.2620"></a>
-<span class="sourceLineNo">2621</span>                        scannerLeaseTimeoutPeriod &gt; 0 ? scannerLeaseTimeoutPeriod : rpcTimeout;<a name="line.2621"></a>
-<span class="sourceLineNo">2622</span>                  }<a name="line.2622"></a>
-<span class="sourceLineNo">2623</span>                  // Use half of whichever timeout value was more restrictive... But don't allow<a name="line.2623"></a>
-<span class="sourceLineNo">2624</span>                  // the time limit to be less than the allowable minimum (could cause an<a name="line.2624"></a>
-<span class="sourceLineNo">2625</span>                  // immediatate timeout before scanning any data).<a name="line.2625"></a>
-<span class="sourceLineNo">2626</span>                  timeLimitDelta = Math.max(timeLimitDelta / 2, minimumScanTimeLimitDelta);<a name="line.2626"></a>
-<span class="sourceLineNo">2627</span>                  timeLimit = System.currentTimeMillis() + timeLimitDelta;<a name="line.2627"></a>
-<span class="sourceLineNo">2628</span>                }<a name="line.2628"></a>
-<span class="sourceLineNo">2629</span><a name="line.2629"></a>
-<span class="sourceLineNo">2630</span>                final LimitScope sizeScope =<a name="line.2630"></a>
-<span class="sourceLineNo">2631</span>                    allowPartialResults ? LimitScope.BETWEEN_CELLS : LimitScope.BETWEEN_ROWS;<a name="line.2631"></a>
-<span class="sourceLineNo">2632</span>                final LimitScope timeScope =<a name="line.2632"></a>
-<span class="sourceLineNo">2633</span>                    allowHeartbeatMessages ? LimitScope.BETWEEN_CELLS : LimitScope.BETWEEN_ROWS;<a name="line.2633"></a>
-<span class="sourceLineNo">2634</span><a name="line.2634"></a>
-<span class="sourceLineNo">2635</span>                boolean trackMetrics =<a name="line.2635"></a>
-<span class="sourceLineNo">2636</span>                    request.hasTrackScanMetrics() &amp;&amp; request.getTrackScanMetrics();<a name="line.2636"></a>
+<span class="sourceLineNo">2568</span>            if (bypass != null &amp;&amp; bypass.booleanValue()) {<a name="line.2568"></a>
+<span class="sourceLineNo">2569</span>              done = true;<a name="line.2569"></a>
+<span class="sourceLineNo">2570</span>            }<a name="line.2570"></a>
+<span class="sourceLineNo">2571</span>          }<a name="line.2571"></a>
+<span class="sourceLineNo">2572</span><a name="line.2572"></a>
+<span class="sourceLineNo">2573</span>          if (!done) {<a name="line.2573"></a>
+<span class="sourceLineNo">2574</span>            long maxResultSize = Math.min(scanner.getMaxResultSize(), maxQuotaResultSize);<a name="line.2574"></a>
+<span class="sourceLineNo">2575</span>            if (maxResultSize &lt;= 0) {<a name="line.2575"></a>
+<span class="sourceLineNo">2576</span>              maxResultSize = maxQuotaResultSize;<a name="line.2576"></a>
+<span class="sourceLineNo">2577</span>            }<a name="line.2577"></a>
+<span class="sourceLineNo">2578</span>            // This is cells inside a row. Default size is 10 so if many versions or many cfs,<a name="line.2578"></a>
+<span class="sourceLineNo">2579</span>            // then we'll resize. Resizings show in profiler. Set it higher than 10. For now<a name="line.2579"></a>
+<span class="sourceLineNo">2580</span>            // arbitrary 32. TODO: keep record of general size of results being returned.<a name="line.2580"></a>
+<span class="sourceLineNo">2581</span>            List&lt;Cell&gt; values = new ArrayList&lt;Cell&gt;(32);<a name="line.2581"></a>
+<span class="sourceLineNo">2582</span>            region.startRegionOperation(Operation.SCAN);<a name="line.2582"></a>
+<span class="sourceLineNo">2583</span>            try {<a name="line.2583"></a>
+<span class="sourceLineNo">2584</span>              int i = 0;<a name="line.2584"></a>
+<span class="sourceLineNo">2585</span>              synchronized(scanner) {<a name="line.2585"></a>
+<span class="sourceLineNo">2586</span>                boolean stale = (region.getRegionInfo().getReplicaId() != 0);<a name="line.2586"></a>
+<span class="sourceLineNo">2587</span>                boolean clientHandlesPartials =<a name="line.2587"></a>
+<span class="sourceLineNo">2588</span>                    request.hasClientHandlesPartials() &amp;&amp; request.getClientHandlesPartials();<a name="line.2588"></a>
+<span class="sourceLineNo">2589</span>                boolean clientHandlesHeartbeats =<a name="line.2589"></a>
+<span class="sourceLineNo">2590</span>                    request.hasClientHandlesHeartbeats() &amp;&amp; request.getClientHandlesHeartbeats();<a name="line.2590"></a>
+<span class="sourceLineNo">2591</span><a name="line.2591"></a>
+<span class="sourceLineNo">2592</span>                // On the server side we must ensure that the correct ordering of partial results is<a name="line.2592"></a>
+<span class="sourceLineNo">2593</span>                // returned to the client to allow them to properly reconstruct the partial results.<a name="line.2593"></a>
+<span class="sourceLineNo">2594</span>                // If the coprocessor host is adding to the result list, we cannot guarantee the<a name="line.2594"></a>
+<span class="sourceLineNo">2595</span>                // correct ordering of partial results and so we prevent partial results from being<a name="line.2595"></a>
+<span class="sourceLineNo">2596</span>                // formed.<a name="line.2596"></a>
+<span class="sourceLineNo">2597</span>                boolean serverGuaranteesOrderOfPartials = results.isEmpty();<a name="line.2597"></a>
+<span class="sourceLineNo">2598</span>                boolean allowPartialResults =<a name="line.2598"></a>
+<span class="sourceLineNo">2599</span>                    clientHandlesPartials &amp;&amp; serverGuaranteesOrderOfPartials &amp;&amp; !isSmallScan;<a name="line.2599"></a>
+<span class="sourceLineNo">2600</span>                boolean moreRows = false;<a name="line.2600"></a>
+<span class="sourceLineNo">2601</span><a name="line.2601"></a>
+<span class="sourceLineNo">2602</span>                // Heartbeat messages occur when the processing of the ScanRequest is exceeds a<a name="line.2602"></a>
+<span class="sourceLineNo">2603</span>                // certain time threshold on the server. When the time threshold is exceeded, the<a name="line.2603"></a>
+<span class="sourceLineNo">2604</span>                // server stops the scan and sends back whatever Results it has accumulated within<a name="line.2604"></a>
+<span class="sourceLineNo">2605</span>                // that time period (may be empty). Since heartbeat messages have the potential to<a name="line.2605"></a>
+<span class="sourceLineNo">2606</span>                // create partial Results (in the event that the timeout occurs in the middle of a<a name="line.2606"></a>
+<span class="sourceLineNo">2607</span>                // row), we must only generate heartbeat messages when the client can handle both<a name="line.2607"></a>
+<span class="sourceLineNo">2608</span>                // heartbeats AND partials<a name="line.2608"></a>
+<span class="sourceLineNo">2609</span>                boolean allowHeartbeatMessages = clientHandlesHeartbeats &amp;&amp; allowPartialResults;<a name="line.2609"></a>
+<span class="sourceLineNo">2610</span><a name="line.2610"></a>
+<span class="sourceLineNo">2611</span>                // Default value of timeLimit is negative to indicate no timeLimit should be<a name="line.2611"></a>
+<span class="sourceLineNo">2612</span>                // enforced.<a name="line.2612"></a>
+<span class="sourceLineNo">2613</span>                long timeLimit = -1;<a name="line.2613"></a>
+<span class="sourceLineNo">2614</span><a name="line.2614"></a>
+<span class="sourceLineNo">2615</span>                // Set the time limit to be half of the more restrictive timeout value (one of the<a name="line.2615"></a>
+<span class="sourceLineNo">2616</span>                // timeout values must be positive). In the event that both values are positive, the<a name="line.2616"></a>
+<span class="sourceLineNo">2617</span>                // more restrictive of the two is used to calculate the limit.<a name="line.2617"></a>
+<span class="sourceLineNo">2618</span>                if (allowHeartbeatMessages &amp;&amp; (scannerLeaseTimeoutPeriod &gt; 0 || rpcTimeout &gt; 0)) {<a name="line.2618"></a>
+<span class="sourceLineNo">2619</span>                  long timeLimitDelta;<a name="line.2619"></a>
+<span class="sourceLineNo">2620</span>                  if (scannerLeaseTimeoutPeriod &gt; 0 &amp;&amp; rpcTimeout &gt; 0) {<a name="line.2620"></a>
+<span class="sourceLineNo">2621</span>                    timeLimitDelta = Math.min(scannerLeaseTimeoutPeriod, rpcTimeout);<a name="line.2621"></a>
+<span class="sourceLineNo">2622</span>                  } else {<a name="line.2622"></a>
+<span class="sourceLineNo">2623</span>                    timeLimitDelta =<a name="line.2623"></a>
+<span class="sourceLineNo">2624</span>                        scannerLeaseTimeoutPeriod &gt; 0 ? scannerLeaseTimeoutPeriod : rpcTimeout;<a name="line.2624"></a>
+<span class="sourceLineNo">2625</span>                  }<a name="line.2625"></a>
+<span class="sourceLineNo">2626</span>                  // Use half of whichever timeout value was more restrictive... But don't allow<a name="line.2626"></a>
+<span class="sourceLineNo">2627</span>                  // the time limit to be less than the allowable minimum (could cause an<a name="line.2627"></a>
+<span class="sourceLineNo">2628</span>                  // immediatate timeout before scanning any data).<a name="line.2628"></a>
+<span class="sourceLineNo">2629</span>                  timeLimitDelta = Math.max(timeLimitDelta / 2, minimumScanTimeLimitDelta);<a name="line.2629"></a>
+<span class="sourceLineNo">2630</span>                  timeLimit = System.currentTimeMillis() + timeLimitDelta;<a name="line.2630"></a>
+<span class="sourceLineNo">2631</span>                }<a name="line.2631"></a>
+<span class="sourceLineNo">2632</span><a name="line.2632"></a>
+<span class="sourceLineNo">2633</span>                final LimitScope sizeScope =<a name="line.2633"></a>
+<span class="sourceLineNo">2634</span>                    allowPartialResults ? LimitScope.BETWEEN_CELLS : LimitScope.BETWEEN_ROWS;<a name="line.2634"></a>
+<span class="sourceLineNo">2635</span>                final LimitScope timeScope =<a name="line.2635"></a>
+<span class="sourceLineNo">2636</span>                    allowHeartbeatMessages ? LimitScope.BETWEEN_CELLS : LimitScope.BETWEEN_ROWS;<a name="line.2636"></a>
 <span class="sourceLineNo">2637</span><a name="line.2637"></a>
-<span class="sourceLineNo">2638</span>                // Configure with limits for this RPC. Set keep progress true since size progress<a name="line.2638"></a>
-<span class="sourceLineNo">2639</span>                // towards size limit should be kept between calls to nextRaw<a name="line.2639"></a>
-<span class="sourceLineNo">2640</span>                ScannerContext.Builder contextBuilder = ScannerContext.newBuilder(true);<a name="line.2640"></a>
-<span class="sourceLineNo">2641</span>                contextBuilder.setSizeLimit(sizeScope, maxResultSize);<a name="line.2641"></a>
-<span class="sourceLineNo">2642</span>                contextBuilder.setBatchLimit(scanner.getBatch());<a name="line.2642"></a>
-<span class="sourceLineNo">2643</span>                contextBuilder.setTimeLimit(timeScope, timeLimit);<a name="line.2643"></a>
-<span class="sourceLineNo">2644</span>                contextBuilder.setTrackMetrics(trackMetrics);<a name="line.2644"></a>
-<span class="sourceLineNo">2645</span>                ScannerContext scannerContext = contextBuilder.build();<a name="line.2645"></a>
-<span class="sourceLineNo">2646</span>                boolean limitReached = false;<a name="line.2646"></a>
-<span class="sourceLineNo">2647</span>                while (i &lt; rows) {<a name="line.2647"></a>
-<span class="sourceLineNo">2648</span>                  // Reset the batch progress to 0 before every call to RegionScanner#nextRaw. The<a name="line.2648"></a>
-<span class="sourceLineNo">2649</span>                  // batch limit is a limit on the number of cells per Result. Thus, if progress is<a name="line.2649"></a>
-<span class="sourceLineNo">2650</span>                  // being tracked (i.e. scannerContext.keepProgress() is true) then we need to<a name="line.2650"></a>
-<span class="sourceLineNo">2651</span>                  // reset the batch progress between nextRaw invocations since we don't want the<a name="line.2651"></a>
-<span class="sourceLineNo">2652</span>                  // batch progress from previous calls to affect future calls<a name="line.2652"></a>
-<span class="sourceLineNo">2653</span>                  scannerContext.setBatchProgress(0);<a name="line.2653"></a>
-<span class="sourceLineNo">2654</span><a name="line.2654"></a>
-<span class="sourceLineNo">2655</span>                  // Collect values to be returned here<a name="line.2655"></a>
-<span class="sourceLineNo">2656</span>                  moreRows = scanner.nextRaw(values, scannerContext);<a name="line.2656"></a>
+<span class="sourceLineNo">2638</span>                boolean trackMetrics =<a name="line.2638"></a>
+<span class="sourceLineNo">2639</span>                    request.hasTrackScanMetrics() &amp;&amp; request.getTrackScanMetrics();<a name="line.2639"></a>
+<span class="sourceLineNo">2640</span><a name="line.2640"></a>
+<span class="sourceLineNo">2641</span>                // Configure with limits for this RPC. Set keep progress true since size progress<a name="line.2641"></a>
+<span class="sourceLineNo">2642</span>                // towards size limit should be kept between calls to nextRaw<a name="line.2642"></a>
+<span class="sourceLineNo">2643</span>                ScannerContext.Builder contextBuilder = ScannerContext.newBuilder(true);<a name="line.2643"></a>
+<span class="sourceLineNo">2644</span>                contextBuilder.setSizeLimit(sizeScope, maxResultSize);<a name="line.2644"></a>
+<span class="sourceLineNo">2645</span>                contextBuilder.setBatchLimit(scanner.getBatch());<a name="line.2645"></a>
+<span class="sourceLineNo">2646</span>                contextBuilder.setTimeLimit(timeScope, timeLimit);<a name="line.2646"></a>
+<span class="sourceLineNo">2647</span>                contextBuilder.setTrackMetrics(trackMetrics);<a name="line.2647"></a>
+<span class="sourceLineNo">2648</span>                ScannerContext scannerContext = contextBuilder.build();<a name="line.2648"></a>
+<span class="sourceLineNo">2649</span>                boolean limitReached = false;<a name="line.2649"></a>
+<span class="sourceLineNo">2650</span>                while (i &lt; rows) {<a name="line.2650"></a>
+<span class="sourceLineNo">2651</span>                  // Reset the batch progress to 0 before every call to RegionScanner#nextRaw. The<a name="line.2651"></a>
+<span class="sourceLineNo">2652</span>                  // batch limit is a limit on the number of cells per Result. Thus, if progress is<a name="line.2652"></a>
+<span class="sourceLineNo">2653</span>                  // being tracked (i.e. scannerContext.keepProgress() is true) then we need to<a name="line.2653"></a>
+<span class="sourceLineNo">2654</span>                  // reset the batch progress between nextRaw invocations since we don't want the<a name="line.2654"></a>
+<span class="sourceLineNo">2655</span>                  // batch progress from previous calls to affect future calls<a name="line.2655"></a>
+<span class="sourceLineNo">2656</span>                  scannerContext.setBatchProgress(0);<a name="line.2656"></a>
 <span class="sourceLineNo">2657</span><a name="line.2657"></a>
-<span class="sourceLineNo">2658</span>                  if (!values.isEmpty()) {<a name="line.2658"></a>
-<span class="sourceLineNo">2659</span>                    final boolean partial = scannerContext.partialResultFormed();<a name="line.2659"></a>
-<span class="sourceLineNo">2660</span>                    Result r = Result.create(values, null, stale, partial);<a name="line.2660"></a>
-<span class="sourceLineNo">2661</span>                    lastBlock = addSize(context, r, lastBlock);<a name="line.2661"></a>
-<span class="sourceLineNo">2662</span>                    results.add(r);<a name="line.2662"></a>
-<span class="sourceLineNo">2663</span>                    i++;<a name="line.2663"></a>
-<span class="sourceLineNo">2664</span>                  }<a name="line.2664"></a>
-<span class="sourceLineNo">2665</span><a name="line.2665"></a>
-<span class="sourceLineNo">2666</span>                  boolean sizeLimitReached = scannerContext.checkSizeLimit(LimitScope.BETWEEN_ROWS);<a name="line.2666"></a>
-<span class="sourceLineNo">2667</span>                  boolean timeLimitReached = scannerContext.checkTimeLimit(LimitScope.BETWEEN_ROWS);<a name="line.2667"></a>
-<span class="sourceLineNo">2668</span>                  boolean rowLimitReached = i &gt;= rows;<a name="line.2668"></a>
-<span class="sourceLineNo">2669</span>                  limitReached = sizeLimitReached || timeLimitReached || rowLimitReached;<a name="line.2669"></a>
-<span class="sourceLineNo">2670</span><a name="line.2670"></a>
-<span class="sourceLineNo">2671</span>                  if (limitReached || !moreRows) {<a name="line.2671"></a>
-<span class="sourceLineNo">2672</span>                    if (LOG.isTraceEnabled()) {<a name="line.2672"></a>
-<span class="sourceLineNo">2673</span>                      LOG.trace("Done scanning. limitReached: " + limitReached + " moreRows: "<a name="line.2673"></a>
-<span class="sourceLineNo">2674</span>                          + moreRows + " scannerContext: " + scannerContext);<a name="line.2674"></a>
-<span class="sourceLineNo">2675</span>                    }<a name="line.2675"></a>
-<span class="sourceLineNo">2676</span>                    // We only want to mark a ScanResponse as a heartbeat message in the event that<a name="line.2676"></a>
-<span class="sourceLineNo">2677</span>                    // there are more values to be read server side. If there aren't more values,<a name="line.2677"></a>
-<span class="sourceLineNo">2678</span>                    // marking it as a heartbeat is wasteful because the client will need to issue<a name="line.2678"></a>
-<span class="sourceLineNo">2679</span>                    // another ScanRequest only to realize that they already have all the values<a name="line.2679"></a>
-<span class="sourceLineNo">2680</span>                    if (moreRows) {<a name="line.2680"></a>
-<span class="sourceLineNo">2681</span>                      // Heartbeat messages occur when the time limit has been reached.<a name="line.2681"></a>
-<span class="sourceLineNo">2682</span>                      builder.setHeartbeatMessage(timeLimitReached);<a name="line.2682"></a>
-<span class="sourceLineNo">2683</span>                    }<a name="line.2683"></a>
-<span class="sourceLineNo">2684</span>                    break;<a name="line.2684"></a>
-<span class="sourceLineNo">2685</span>                  }<a name="line.2685"></a>
-<span class="sourceLineNo">2686</span>                  values.clear();<a name="line.2686"></a>
-<span class="sourceLineNo">2687</span>                }<a name="line.2687"></a>
-<span class="sourceLineNo">2688</span><a name="line.2688"></a>
-<span class="sourceLineNo">2689</span>                if (limitReached || moreRows) {<a name="line.2689"></a>
-<span class="sourceLineNo">2690</span>                  // We stopped prematurely<a name="line.2690"></a>
-<span class="sourceLineNo">2691</span>                  builder.setMoreResultsInRegion(true);<a name="line.2691"></a>
-<span class="sourceLineNo">2692</span>                } else {<a name="line.2692"></a>
-<span class="sourceLineNo">2693</span>                  // We didn't get a single batch<a name="line.2693"></a>
-<span class="sourceLineNo">2694</span>                  builder.setMoreResultsInRegion(false);<a name="line.2694"></a>
-<span class="sourceLineNo">2695</span>                }<a name="line.2695"></a>
-<span class="sourceLineNo">2696</span><a name="line.2696"></a>
-<span class="sourceLineNo">2697</span>                // Check to see if the client requested that we track metrics server side. If the<a name="line.2697"></a>
-<span class="sourceLineNo">2698</span>                // client requested metrics, retrieve the metrics from the scanner context.<a name="line.2698"></a>
-<span class="sourceLineNo">2699</span>                if (trackMetrics) {<a name="line.2699"></a>
-<span class="sourceLineNo">2700</span>                  Map&lt;String, Long&gt; metrics = scannerContext.getMetrics().getMetricsMap();<a name="line.2700"></a>
-<span class="sourceLineNo">2701</span>                  ScanMetrics.Builder metricBuilder = ScanMetrics.newBuilder();<a name="line.2701"></a>
-<span class="sourceLineNo">2702</span>                  NameInt64Pair.Builder pairBuilder = NameInt64Pair.newBuilder();<a name="line.2702"></a>
-<span class="sourceLineNo">2703</span><a name="line.2703"></a>
-<span class="sourceLineNo">2704</span>                  for (Entry&lt;String, Long&gt; entry : metrics.entrySet()) {<a name="line.2704"></a>
-<span class="sourceLineNo">2705</span>                    pairBuilder.setName(entry.getKey());<a name="line.2705"></a>
-<span class="sourceLineNo">2706</span>                    pairBuilder.setValue(entry.getValue());<a name="line.2706"></a>
-<span class="sourceLineNo">2707</span>                    metricBuilder.addMetrics(pairBuilder.build());<a name="line.2707"></a>
-<span class="sourceLineNo">2708</span>                  }<a name="line.2708"></a>
-<span class="sourceLineNo">2709</span><a name="line.2709"></a>
-<span class="sourceLineNo">2710</span>                  builder.setScanMetrics(metricBuilder.build());<a name="line.2710"></a>
-<span class="sourceLineNo">2711</span>                }<a name="line.2711"></a>
-<span class="sourceLineNo">2712</span>              }<a name="line.2712"></a>
-<span class="sourceLineNo">2713</span>              region.updateReadRequestsCount(i);<a name="line.2713"></a>
-<span class="sourceLineNo">2714</span>              long responseCellSize = context != null ? context.getResponseCellSize() : 0;<a name="line.2714"></a>
-<span class="sourceLineNo">2715</span>              region.getMetrics().updateScanNext(responseCellSize);<a name="line.2715"></a>
-<span class="sourceLineNo">2716</span>              if (regionServer.metricsRegionServer != null) {<a name="line.2716"></a>
-<span class="sourceLineNo">2717</span>                regionServer.metricsRegionServer.updateScannerNext(responseCellSize);<a name="line.2717"></a>
-<span class="sourceLineNo">2718</span>              }<a name="line.2718"></a>
-<span class="sourceLineNo">2719</span>            } finally {<a name="line.2719"></a>
-<span class="sourceLineNo">2720</span>              region.closeRegionOperation();<a name="line.2720"></a>
-<span class="sourceLineNo">2721</span>            }<a name="line.2721"></a>
-<span class="sourceLineNo">2722</span>            // coprocessor postNext hook<a name="line.2722"></a>
-<span class="sourceLineNo">2723</span>            if (region != null &amp;&amp; region.getCoprocessorHost() != null) {<a name="line.2723"></a>
-<span class="sourceLineNo">2724</span>              region.getCoprocessorHost().postScannerNext(scanner, results, rows, true);<a name="line.2724"></a>
-<span class="sourceLineNo">2725</span>            }<a name="line.2725"></a>
-<span class="sourceLineNo">2726</span>          }<a name="line.2726"></a>
-<span class="sourceLineNo">2727</span><a name="line.2727"></a>
-<span class="sourceLineNo">2728</span>          quota.addScanResult(results);<a name="line.2728"></a>
-<span class="sourceLineNo">2729</span><a name="line.2729"></a>
-<span class="sourceLineNo">2730</span>          // If the scanner's filter - if any - is done with the scan<a name="line.2730"></a>
-<span class="sourceLineNo">2731</span>          // and wants to tell the client to stop the scan. This is done by passing<a name="line.2731"></a>
-<span class="sourceLineNo">2732</span>          // a null result, and setting moreResults to false.<a name="line.2732"></a>
-<span class="sourceLineNo">2733</span>          if (scanner.isFilterDone() &amp;&amp; results.isEmpty()) {<a name="line.2733"></a>
-<span class="sourceLineNo">2734</span>            moreResults = false;<a name="line.2734"></a>
-<span class="sourceLineNo">2735</span>            results = null;<a name="line.2735"></a>
-<span class="sourceLineNo">2736</span>          } else {<a name="line.2736"></a>
-<span class="sourceLineNo">2737</span>            addResults(builder, results, controller,<a name="line.2737"></a>
-<span class="sourceLineNo">2738</span>                RegionReplicaUtil.isDefaultReplica(region.getRegionInfo()),<a name="line.2738"></a>
-<span class="sourceLineNo">2739</span>                isClientCellBlockSupport(context));<a name="line.2739"></a>
-<span class="sourceLineNo">2740</span>          }<a name="line.2740"></a>
-<span class="sourceLineNo">2741</span>        } catch (IOException e) {<a name="line.2741"></a>
-<span class="sourceLineNo">2742</span>          // if we have an exception on scanner next and we are using the callSeq<a name="line.2742"></a>
-<span class="sourceLineNo">2743</span>          // we should rollback because the client will retry with the same callSeq<a name="line.2743"></a>
-<span class="sourceLineNo">2744</span>          // and get an OutOfOrderScannerNextException if we don't do so.<a name="line.2744"></a>
-<span class="sourceLineNo">2745</span>          if (rsh != null &amp;&amp; request.hasNextCallSeq()) {<a name="line.2745"></a>
-<span class="sourceLineNo">2746</span>            rsh.rollbackNextCallSeq();<a name="line.2746"></a>
-<span class="sourceLineNo">2747</span>          }<a name="line.2747"></a>
-<span class="sourceLineNo">2748</span>          throw e;<a name="line.2748"></a>
-<span class="sourceLineNo">2749</span>        } finally {<a name="line.2749"></a>
-<span class="sourceLineNo">2750</span>          if (context != null) {<a name="line.2750"></a>
-<span class="sourceLineNo">2751</span>            context.setCallBack(rsh.shippedCallback);<a name="line.2751"></a>
-<span class="sourceLineNo">2752</span>          }<a name="line.2752"></a>
-<span class="sourceLineNo">2753</span>          // Adding resets expiration time on lease.<a name="line.2753"></a>
-<span class="sourceLineNo">2754</span>          if (scanners.containsKey(scannerName)) {<a name="line.2754"></a>
-<span class="sourceLineNo">2755</span>            ttl = this.scannerLeaseTimeoutPeriod;<a name="line.2755"></a>
-<span class="sourceLineNo">2756</span>            // When context != null, adding back the lease will be done in callback set above.<a name="line.2756"></a>
-<span class="sourceLineNo">2757</span>            if (context == null) {<a name="line.2757"></a>
-<span class="sourceLineNo">2758</span>              if (lease != null) regionServer.leases.addLease(lease);<a name="line.2758"></a>
-<span class="sourceLineNo">2759</span>            }<a name="line.2759"></a>
-<span class="sourceLineNo">2760</span>          }<a name="line.2760"></a>
-<span class="sourceLineNo">2761</span>        }<a name="line.2761"></a>
-<span class="sourceLineNo">2762</span>      }<a name="line.2762"></a>
-<span class="sourceLineNo">2763</span><a name="line.2763"></a>
-<span class="sourceLineNo">2764</span>      if (!moreResults || closeScanner) {<a name="line.2764"></a>
-<span class="sourceLineNo">2765</span>        ttl = 0;<a name="line.2765"></a>
-<span class="sourceLineNo">2766</span>        moreResults = false;<a name="line.2766"></a>
-<span class="sourceLineNo">2767</span>        if (region != null &amp;&amp; region.getCoprocessorHost() != null) {<a name="line.2767"></a>
-<span class="sourceLineNo">2768</span>          if (region.getCoprocessorHost().preScannerClose(scanner)) {<a name="line.2768"></a>
-<span class="sourceLineNo">2769</span>            return builder.build(); // bypass<a name="line.2769"></a>
-<span class="sourceLineNo">2770</span>          }<a name="line.2770"></a>
-<span class="sourceLineNo">2771</span>        }<a name="line.2771"></a>
-<span class="sourceLineNo">2772</span>        rsh = scanners.remove(scannerName);<a name="line.2772"></a>
-<span class="sourceLineNo">2773</span>        if (rsh != null) {<a name="line.2773"></a>
-<span class="sourceLineNo">2774</span>          if (context != null) {<a name="line.2774"></a>
-<span class="sourceLineNo">2775</span>            context.setCallBack(rsh.closeCallBack);<a name="line.2775"></a>
-<span class="sourceLineNo">2776</span>          } else {<a name="line.2776"></a>
-<span class="sourceLineNo">2777</span>            rsh.s.close();<a name="line.2777"></a>
-<span class="sourceLineNo">2778</span>          }<a name="line.2778"></a>
-<span class="sourceLineNo">2779</span>          try {<a name="line.2779"></a>
-<span class="sourceLineNo">2780</span>            regionServer.leases.cancelLease(scannerName);<a name="line.2780"></a>
-<span class="sourceLineNo">2781</span>          } catch (LeaseException le) {<a name="line.2781"></a>
-<span class="sourceLineNo">2782</span>            // No problem, ignore<a name="line.2782"></a>
-<span class="sourceLineNo">2783</span>            if (LOG.isTraceEnabled()) {<a name="line.2783"></a>
-<span class="sourceLineNo">2784</span>              LOG.trace("Un-able to cancel lease of scanner. It could already be closed.");<a name="line.2784"></a>
-<span class="sourceLineNo">2785</span>            }<a name="line.2785"></a>
-<span class="sourceLineNo">2786</span>          }<a name="line.2786"></a>
-<span class="sourceLineNo">2787</span>          if (region != null &amp;&amp; region.getCoprocessorHost() != null) {<a name="line.2787"></a>
-<span class="sourceLineNo">2788</span>            region.getCoprocessorHost().postScannerClose(scanner);<a name="line.2788"></a>
+<span class="sourceLineNo">2658</span>                  // Collect values to be returned here<a name="line.2658"></a>
+<span class="sourceLineNo">2659</span>                  moreRows = scanner.nextRaw(values, scannerContext);<a name="line.2659"></a>
+<span class="sourceLineNo">2660</span><a name="line.2660"></a>
+<span class="sourceLineNo">2661</span>                  if (!values.isEmpty()) {<a name="line.2661"></a>
+<span class="sourceLineNo">2662</span>                    final boolean partial = scannerContext.partialResultFormed();<a name="line.2662"></a>
+<span class="sourceLineNo">2663</span>                    Result r = Result.create(values, null, stale, partial);<a name="line.2663"></a>
+<span class="sourceLineNo">2664</span>                    lastBlock = addSize(context, r, lastBlock);<a name="line.2664"></a>
+<span class="sourceLineNo">2665</span>                    results.add(r);<a name="line.2665"></a>
+<span class="sourceLineNo">2666</span>                    i++;<a name="line.2666"></a>
+<span class="sourceLineNo">2667</span>                  }<a name="line.2667"></a>
+<span class="sourceLineNo">2668</span><a name="line.2668"></a>
+<span class="sourceLineNo">2669</span>                  boolean sizeLimitReached = scannerContext.checkSizeLimit(LimitScope.BETWEEN_ROWS);<a name="line.2669"></a>
+<span class="sourceLineNo">2670</span>                  boolean timeLimitReached = scannerContext.checkTimeLimit(LimitScope.BETWEEN_ROWS);<a name="line.2670"></a>
+<span class="sourceLineNo">2671</span>                  boolean rowLimitReached = i &gt;= rows;<a name="line.2671"></a>
+<span class="sourceLineNo">2672</span>                  limitReached = sizeLimitReached || timeLimitReached || rowLimitReached;<a name="line.2672"></a>
+<span class="sourceLineNo">2673</span><a name="line.2673"></a>
+<span class="sourceLineNo">2674</span>                  if (limitReached || !moreRows) {<a name="line.2674"></a>
+<span class="sourceLineNo">2675</span>                    if (LOG.isTraceEnabled()) {<a name="line.2675"></a>
+<span class="sourceLineNo">2676</span>                      LOG.trace("Done scanning. limitReached: " + limitReached + " moreRows: "<a name="line.2676"></a>
+<span class="sourceLineNo">2677</span>                          + moreRows + " scannerContext: " + scannerContext);<a name="line.2677"></a>
+<span class="sourceLineNo">2678</span>                    }<a name="line.2678"></a>
+<span class="sourceLineNo">2679</span>                    // We only want to mark a ScanResponse as a heartbeat message in the event that<a name="line.2679"></a>
+<span class="sourceLineNo">2680</span>                    // there are more values to be read server side. If there aren't more values,<a name="line.2680"></a>
+<span class="sourceLineNo">2681</span>                    // marking it as a heartbeat is wasteful because the client will need to issue<a name="line.2681"></a>
+<span class="sourceLineNo">2682</span>                    // another ScanRequest only to realize that they already have all the values<a name="line.2682"></a>
+<span class="sourceLineNo">2683</span>                    if (moreRows) {<a name="line.2683"></a>
+<span class="sourceLineNo">2684</span>                      // Heartbeat messages occur when the time limit has been reached.<a name="line.2684"></a>
+<span class="sourceLineNo">2685</span>                      builder.setHeartbeatMessage(timeLimitReached);<a name="line.2685"></a>
+<span class="sourceLineNo">2686</span>                    }<a name="line.2686"></a>
+<span class="sourceLineNo">2687</span>                    break;<a name="line.2687"></a>
+<span class="sourceLineNo">2688</span>                  }<a name="line.2688"></a>
+<span class="sourceLineNo">2689</span>                  values.clear();<a name="line.2689"></a>
+<span class="sourceLineNo">2690</span>                }<a name="line.2690"></a>
+<span class="sourceLineNo">2691</span><a name="line.2691"></a>
+<span class="sourceLineNo">2692</span>                if (limitReached || moreRows) {<a name="line.2692"></a>
+<span class="sourceLineNo">2693</span>                  // We stopped prematurely<a name="line.2693"></a>
+<span class="sourceLineNo">2694</span>                  builder.setMoreResultsInRegion(true);<a name="line.2694"></a>
+<span class="sourceLineNo">2695</span>                } else {<a name="line.2695"></a>
+<span class="sourceLineNo">2696</span>                  // We didn't get a single batch<a name="line.2696"></a>
+<span class="sourceLineNo">2697</span>                  builder.setMoreResultsInRegion(false);<a name="line.2697"></a>
+<span class="sourceLineNo">2698</span>                }<a name="line.2698"></a>
+<span class="sourceLineNo">2699</span><a name="line.2699"></a>
+<span class="sourceLineNo">2700</span>                // Check to see if the client requested that we track metrics server side. If the<a name="line.2700"></a>
+<span class="sourceLineNo">2701</span>                // client requested metrics, retrieve the metrics from the scanner context.<a name="line.2701"></a>
+<span class="sourceLineNo">2702</span>                if (trackMetrics) {<a name="line.2702"></a>
+<span class="sourceLineNo">2703</span>                  Map&lt;String, Long&gt; metrics = scannerContext.getMetrics().getMetricsMap();<a name="line.2703"></a>
+<span class="sourceLineNo">2704</span>                  ScanMetrics.Builder metricBuilder = ScanMetrics.newBuilder();<a name="line.2704"></a>
+<span class="sourceLineNo">2705</span>                  NameInt64Pair.Builder pairBuilder = NameInt64Pair.newBuilder();<a name="line.2705"></a>
+<span class="sourceLineNo">2706</span><a name="line.2706"></a>
+<span class="sourceLineNo">2707</span>                  for (Entry&lt;String, Long&gt; entry : metrics.entrySet()) {<a name="line.2707"></a>
+<span class="sourceLineNo">2708</span>                    pairBuilder.setName(entry.getKey());<a name="line.2708"></a>
+<span class="sourceLineNo">2709</span>                    pairBuilder.setValue(entry.getValue());<a name="line.2709"></a>
+<span class="sourceLineNo">2710</span>                    metricBuilder.addMetrics(pairBuilder.build());<a name="line.2710"></a>
+<span class="sourceLineNo">2711</span>                  }<a name="line.2711"></a>
+<span class="sourceLineNo">2712</span><a name="line.2712"></a>
+<span class="sourceLineNo">2713</span>                  builder.setScanMetrics(metricBuilder.build());<a name="line.2713"></a>
+<span class="sourceLineNo">2714</span>                }<a name="line.2714"></a>
+<span class="sourceLineNo">2715</span>              }<a name="line.2715"></a>
+<span class="sourceLineNo">2716</span>              region.updateReadRequestsCount(i);<a name="line.2716"></a>
+<span class="sourceLineNo">2717</span>              long responseCellSize = context != null ? context.getResponseCellSize() : 0;<a name="line.2717"></a>
+<span class="sourceLineNo">2718</span>              region.getMetrics().updateScanNext(responseCellSize);<a name="line.2718"></a>
+<span class="sourceLineNo">2719</span>              if (regionServer.metricsRegionServer != null) {<a name="line.2719"></a>
+<span class="sourceLineNo">2720</span>                regionServer.metricsRegionServer.updateScannerNext(responseCellSize);<a name="line.2720"></a>
+<span class="sourceLineNo">2721</span>              }<a name="line.2721"></a>
+<span class="sourceLineNo">2722</span>            } finally {<a name="line.2722"></a>
+<span class="sourceLineNo">2723</span>              region.closeRegionOperation();<a name="line.2723"></a>
+<span class="sourceLineNo">2724</span>            }<a name="line.2724"></a>
+<span class="sourceLineNo">2725</span>            // coprocessor postNext hook<a name="line.2725"></a>
+<span class="sourceLineNo">2726</span>            if (region != null &amp;&amp; region.getCoprocessorHost() != null) {<a name="line.2726"></a>
+<span class="sourceLineNo">2727</span>              region.getCoprocessorHost().postScannerNext(scanner, results, rows, true);<a name="line.2727"></a>
+<span class="sourceLineNo">2728</span>            }<a name="line.2728"></a>
+<span class="sourceLineNo">2729</span>          }<a name="line.2729"></a>
+<span class="sourceLineNo">2730</span><a name="line.2730"></a>
+<span class="sourceLineNo">2731</span>          quota.addScanResult(results);<a name="line.2731"></a>
+<span class="sourceLineNo">2732</span><a name="line.2732"></a>
+<span class="sourceLineNo">2733</span>          // If the scanner's filter - if any - is done with the scan<a name="line.2733"></a>
+<span class="sourceLineNo">2734</span>          // and wants to tell the client to stop the scan. This is done by passing<a name="line.2734"></a>
+<span class="sourceLineNo">2735</span>          // a null result, and setting moreResults to false.<a name="line.2735"></a>
+<span class="sourceLineNo">2736</span>          if (scanner.isFilterDone() &amp;&amp; results.isEmpty()) {<a name="line.2736"></a>
+<span class="sourceLineNo">2737</span>            moreResults = false;<a name="line.2737"></a>
+<span class="sourceLineNo">2738</span>            results = null;<a name="line.2738"></a>
+<span class="sourceLineNo">2739</span>          } else {<a name="line.2739"></a>
+<span class="sourceLineNo">2740</span>            addResults(builder, results, controller,<a name="line.2740"></a>
+<span class="sourceLineNo">2741</span>                RegionReplicaUtil.isDefaultReplica(region.getRegionInfo()),<a name="line.2741"></a>
+<span class="sourceLineNo">2742</span>                isClientCellBlockSupport(context));<a name="line.2742"></a>
+<span class="sourceLineNo">2743</span>          }<a name="line.2743"></a>
+<span class="sourceLineNo">2744</span>        } catch (IOException e) {<a name="line.2744"></a>
+<span class="sourceLineNo">2745</span>          // if we have an exception on scanner next and we are using the callSeq<a name="line.2745"></a>
+<span class="sourceLineNo">2746</span>          // we should rollback because the client will retry with the same callSeq<a name="line.2746"></a>
+<span class="sourceLineNo">2747</span>          // and get an OutOfOrderScannerNextException if we don't do so.<a name="line.2747"></a>
+<span class="sourceLineNo">2748</span>          if (rsh != null &amp;&amp; request.hasNextCallSeq()) {<a name="line.2748"></a>
+<span class="sourceLineNo">2749</span>            rsh.rollbackNextCallSeq();<a name="line.2749"></a>
+<span class="sourceLineNo">2750</span>          }<a name="line.2750"></a>
+<span class="sourceLineNo">2751</span>          throw e;<a name="line.2751"></a>
+<span class="sourceLineNo">2752</span>        } finally {<a name="line.2752"></a>
+<span class="sourceLineNo">2753</span>          if (context != null) {<a name="line.2753"></a>
+<span class="sourceLineNo">2754</span>            context.setCallBack(rsh.shippedCallback);<a name="line.2754"></a>
+<span class="sourceLineNo">2755</span>          }<a name="line.2755"></a>
+<span class="sourceLineNo">2756</span>          // Adding resets expiration time on lease.<a name="line.2756"></a>
+<span class="sourceLineNo">2757</span>          if (scanners.containsKey(scannerName)) {<a name="line.2757"></a>
+<span class="sourceLineNo">2758</span>            ttl = this.scannerLeaseTimeoutPeriod;<a name="line.2758"></a>
+<span class="sourceLineNo">2759</span>            // When context != null, adding back the lease will be done in callback set above.<a name="line.2759"></a>
+<span class="sourceLineNo">2760</span>            if (context == null) {<a name="line.2760"></a>
+<span class="sourceLineNo">2761</span>              if (lease != null) regionServer.leases.addLease(lease);<a name="line.2761"></a>
+<span class="sourceLineNo">2762</span>            }<a name="line.2762"></a>
+<span class="sourceLineNo">2763</span>          }<a name="line.2763"></a>
+<span class="sourceLineNo">2764</span>        }<a name="line.2764"></a>
+<span class="sourceLineNo">2765</span>      }<a name="line.2765"></a>
+<span class="sourceLineNo">2766</span><a name="line.2766"></a>
+<span class="sourceLineNo">2767</span>      if (!moreResults || closeScanner) {<a name="line.2767"></a>
+<span class="sourceLineNo">2768</span>        ttl = 0;<a name="line.2768"></a>
+<span class="sourceLineNo">2769</span>        moreResults = false;<a name="line.2769"></a>
+<span class="sourceLineNo">2770</span>        if (region != null &amp;&amp; region.getCoprocessorHost() != null) {<a name="line.2770"></a>
+<span class="sourceLineNo">2771</span>          if (region.getCoprocessorHost().preScannerClose(scanner)) {<a name="line.2771"></a>
+<span class="sourceLineNo">2772</span>            return builder.build(); // bypass<a name="line.2772"></a>
+<span class="sourceLineNo">2773</span>          }<a name="line.2773"></a>
+<span class="sourceLineNo">2774</span>        }<a name="line.2774"></a>
+<span class="sourceLineNo">2775</span>        rsh = scanners.remove(scannerName);<a name="line.2775"></a>
+<span class="sourceLineNo">2776</span>        if (rsh != null) {<a name="line.2776"></a>
+<span class="sourceLineNo">2777</span>          if (context != null) {<a name="line.2777"></a>
+<span class="sourceLineNo">2778</span>            context.setCallBack(rsh.closeCallBack);<a name="line.2778"></a>
+<span class="sourceLineNo">2779</span>          } else {<a name="line.2779"></a>
+<span class="sourceLineNo">2780</span>            rsh.s.close();<a name="line.2780"></a>
+<span class="sourceLineNo">2781</span>          }<a name="line.2781"></a>
+<span class="sourceLineNo">2782</span>          try {<a name="line.2782"></a>
+<span class="sourceLineNo">2783</span>            regionServer.leases.cancelLease(scannerName);<a name="line.2783"></a>
+<span class="sourceLineNo">2784</span>          } catch (LeaseException le) {<a name="line.2784"></a>
+<span class="sourceLineNo">2785</span>            // No problem, ignore<a name="line.2785"></a>
+<span class="sourceLineNo">2786</span>            if (LOG.isTraceEnabled()) {<a name="line.2786"></a>
+<span class="sourceLineNo">2787</span>              LOG.trace("Un-able to cancel lease of scanner. It could already be closed.");<a name="line.2787"></a>
+<span class="sourceLineNo">2788</span>            }<a name="line.2788"></a>
 <span class="sourceLineNo">2789</span>          }<a name="line.2789"></a>
-<span class="sourceLineNo">2790</span>        }<a name="line.2790"></a>
-<span class="sourceLineNo">2791</span>      }<a name="line.2791"></a>
-<span class="sourceLineNo">2792</span><a name="line.2792"></a>
-<span class="sourceLineNo">2793</span>      if (ttl &gt; 0) {<a name="line.2793"></a>
-<span class="sourceLineNo">2794</span>        builder.setTtl(ttl);<a name="line.2794"></a>
-<span class="sourceLineNo">2795</span>      }<a name="line.2795"></a>
-<span class="sourceLineNo">2796</span>      builder.setScannerId(scannerId);<a name="line.2796"></a>
-<span class="sourceLineNo">2797</span>      builder.setMoreResults(moreResults);<a name="line.2797"></a>
-<span class="sourceLineNo">2798</span>      return builder.build();<a name="line.2798"></a>
-<span class="sourceLineNo">2799</span>    } catch (IOException ie) {<a name="line.2799"></a>
-<span class="sourceLineNo">2800</span>      if (scannerName != null &amp;&amp; ie instanceof NotServingRegionException) {<a name="line.2800"></a>
-<span class="sourceLineNo">2801</span>        RegionScannerHolder rsh = scanners.remove(scannerName);<a name="line.2801"></a>
-<span class="sourceLineNo">2802</span>        if (rsh != null) {<a name="line.2802"></a>
-<span class="sourceLineNo">2803</span>          try {<a name="line.2803"></a>
-<span class="sourceLineNo">2804</span>            RegionScanner scanner = rsh.s;<a name="line.2804"></a>
-<span class="sourceLineNo">2805</span>            LOG.warn(scannerName + " encountered " + ie.getMessage() + ", closing ...");<a name="line.2805"></a>
-<span class="sourceLineNo">2806</span>            scanner.close();<a name="line.2806"></a>
-<span class="sourceLineNo">2807</span>            regionServer.leases.cancelLease(scannerName);<a name="line.2807"></a>
-<span class="sourceLineNo">2808</span>          } catch (IOException e) {<a name="line.2808"></a>
-<span class="sourceLineNo">2809</span>           LOG.warn("Getting exception closing " + scannerName, e);<a name="line.2809"></a>
-<span class="sourceLineNo">2810</span>          }<a name="line.2810"></a>
-<span class="sourceLineNo">2811</span>        }<a name="line.2811"></a>
-<span class="sourceLineNo">2812</span>      }<a name="line.2812"></a>
-<span class="sourceLineNo">2813</span>      throw new ServiceException(ie);<a name="line.2813"></a>
-<span class="sourceLineNo">2814</span>    } finally {<a name="line.2814"></a>
-<span class="sourceLineNo">2815</span>      if (quota != null) {<a name="line.2815"></a>
-<span class="sourceLineNo">2816</span>        quota.close();<a name="line.2816"></a>
-<span class="sourceLineNo">2817</span>      }<a name="line.2817"></a>
-<span class="sourceLineNo">2818</span>    }<a name="line.2818"></a>
-<span class="sourceLineNo">2819</span>  }<a name="line.2819"></a>
-<span class="sourceLineNo">2820</span><a name="line.2820"></a>
-<span class="sourceLineNo">2821</span>  @Override<a name="line.2821"></a>
-<span class="sourceLineNo">2822</span>  public CoprocessorServiceResponse execRegionServerService(RpcController controller,<a name="line.2822"></a>
-<span class="sourceLineNo">2823</span>      CoprocessorServiceRequest request) throws ServiceException {<a name="line.2823"></a>
-<span class="sourceLineNo">2824</span>    return regionServer.execRegionServerService(controller, request);<a name="line.2824"></a>
-<span class="sourceLineNo">2825</span>  }<a name="line.2825"></a>
-<span class="sourceLineNo">2826</span><a name="line.2826"></a>
-<span class="sourceLineNo">2827</span>  @Override<a name="line.2827"></a>
-<span class="sourceLineNo">2828</span>  public UpdateConfigurationResponse updateConfiguration(<a name="line.2828"></a>
-<span class="sourceLineNo">2829</span>      RpcController controller, UpdateConfigurationRequest request)<a name="line.2829"></a>
-<span class="sourceLineNo">2830</span>      throws ServiceException {<a name="line.2830"></a>
-<span class="sourceLineNo">2831</span>    try {<a name="line.2831"></a>
-<span class="sourceLineNo">2832</span>      this.regionServer.updateConfiguration();<a name="line.2832"></a>
-<span class="sourceLineNo">2833</span>    } catch (Exception e) {<a name="line.2833"></a>
-<span class="sourceLineNo">2834</span>      throw new ServiceException(e);<a name="line.2834"></a>
-<span class="sourceLineNo">2835</span>    }<a name="line.2835"></a>
-<span class="sourceLineNo">2836</span>    return UpdateConfigurationResponse.getDefaultInstance();<a name="line.2836"></a>
-<span class="sourceLineNo">2837</span>  }<a name="line.2837"></a>
-<span class="sourceLineNo">2838</span>}<a name="line.2838"></a>
+<span class="sourceLineNo">2790</span>          if (region != null &amp;&amp; region.getCoprocessorHost() != null) {<a name="line.2790"></a>
+<span class="sourceLineNo">2791</span>            region.getCoprocessorHost().postScannerClose(scanner);<a name="line.2791"></a>
+<span class="sourceLineNo">2792</span>          }<a name="line.2792"></a>
+<span class="sourceLineNo">2793</span>        }<a name="line.2793"></a>
+<span class="sourceLineNo">2794</span>      }<a name="line.2794"></a>
+<span class="sourceLineNo">2795</span><a name="line.2795"></a>
+<span class="sourceLineNo">2796</span>      if (ttl &gt; 0) {<a name="line.2796"></a>
+<span class="sourceLineNo">2797</span>        builder.setTtl(ttl);<a name="line.2797"></a>
+<span class="sourceLineNo">2798</span>      }<a name="line.2798"></a>
+<span class="sourceLineNo">2799</span>      builder.setScannerId(scannerId);<a name="line.2799"></a>
+<span class="sourceLineNo">2800</span>      builder.setMoreResults(moreResults);<a name="line.2800"></a>
+<span class="sourceLineNo">2801</span>      return builder.build();<a name="line.2801"></a>
+<span class="sourceLineNo">2802</span>    } catch (IOException ie) {<a name="line.2802"></a>
+<span class="sourceLineNo">2803</span>      if (scannerName != null &amp;&amp; ie instanceof NotServingRegionException) {<a name="line.2803"></a>
+<span class="sourceLineNo">2804</span>        RegionScannerHolder rsh = scanners.remove(scannerName);<a name="line.2804"></a>
+<span class="sourceLineNo">2805</span>        if (rsh != null) {<a name="line.2805"></a>
+<span class="sourceLineNo">2806</span>          try {<a name="line.2806"></a>
+<span class="sourceLineNo">2807</span>            RegionScanner scanner = rsh.s;<a name="line.2807"></a>
+<span class="sourceLineNo">2808</span>            LOG.warn(scannerName + " encountered " + ie.getMessage() + ", closing ...");<a name="line.2808"></a>
+<span class="sourceLineNo">2809</span>            scanner.close();<a name="line.2809"></a>
+<span class="sourceLineNo">2810</span>            regionServer.leases.cancelLease(scannerName);<a name="line.2810"></a>
+<span class="sourceLineNo">2811</span>          } catch (IOException e) {<a name="line.2811"></a>
+<span class="sourceLineNo">2812</span>           LOG.warn("Getting exception closing " + scannerName, e);<a name="line.2812"></a>
+<span class="sourceLineNo">2813</span>          }<a name="line.2813"></a>
+<span class="sourceLineNo">2814</span>        }<a name="line.2814"></a>
+<span class="sourceLineNo">2815</span>      }<a name="line.2815"></a>
+<span class="sourceLineNo">2816</span>      throw new ServiceException(ie);<a name="line.2816"></a>
+<span class="sourceLineNo">2817</span>    } finally {<a name="line.2817"></a>
+<span class="sourceLineNo">2818</span>      if (quota != null) {<a name="line.2818"></a>
+<span class="sourceLineNo">2819</span>        quota.close();<a name="line.2819"></a>
+<span class="sourceLineNo">2820</span>      }<a name="line.2820"></a>
+<span class="sourceLineNo">2821</span>    }<a name="line.2821"></a>
+<span class="sourceLineNo">2822</span>  }<a name="line.2822"></a>
+<span class="sourceLineNo">2823</span><a name="line.2823"></a>
+<span class="sourceLineNo">2824</span>  @Override<a name="line.2824"></a>
+<span class="sourceLineNo">2825</span>  public CoprocessorServiceResponse execRegionServerService(RpcController controller,<a name="line.2825"></a>
+<span class="sourceLineNo">2826</span>      CoprocessorServiceRequest request) throws ServiceException {<a name="line.2826"></a>
+<span class="sourceLineNo">2827</span>    return regionServer.execRegionServerService(controller, request);<a name="line.2827"></a>
+<span class="sourceLineNo">2828</span>  }<a name="line.2828"></a>
+<span class="sourceLineNo">2829</span><a name="line.2829"></a>
+<span class="sourceLineNo">2830</span>  @Override<a name="line.2830"></a>
+<span class="sourceLineNo">2831</span>  public UpdateConfigurationResponse updateConfiguration(<a name="line.2831"></a>
+<span class="sourceLineNo">2832</span>      RpcController controller, UpdateConfigurationRequest request)<a name="line.2832"></a>
+<span class="sourceLineNo">2833</span>      throws ServiceException {<a name="line.2833"></a>
+<span class="sourceLineNo">2834</span>    try {<a name="line.2834"></a>
+<span class="sourceLineNo">2835</span>      this.regionServer.updateConfiguration();<a name="line.2835"></a>
+<span class="sourceLineNo">2836</span>    } catch (Exception e) {<a name="line.2836"></a>
+<span class="sourceLineNo">2837</span>      throw new ServiceException(e);<a name="line.2837"></a>
+<span class="sourceLineNo">2838</span>    }<a name="line.2838"></a>
+<span class="sourceLineNo">2839</span>    return UpdateConfigurationResponse.getDefaultInstance();<a name="line.2839"></a>
+<span class="sourceLineNo">2840</span>  }<a name="line.2840"></a>
+<span class="sourceLineNo">2841</span>}<a name="line.2841"></a>