This is an automated email from the ASF dual-hosted git repository.
sijie pushed a commit to branch branch-4.9
in repository https://gitbox.apache.org/repos/asf/bookkeeper.git
The following commit(s) were added to refs/heads/branch-4.9 by this push:
new a35e6c1 Issue #1970: Ensure getStickyReadBookieIndex returns valid
bookie index
a35e6c1 is described below
commit a35e6c157745a86da6e71da8b2711995a322f09b
Author: Sijie Guo <[email protected]>
AuthorDate: Thu Jun 20 20:19:53 2019 -0700
Issue #1970: Ensure getStickyReadBookieIndex returns valid bookie index
Descriptions of the changes in this PR:
Master Issue: #1970
Related Issues: apache/pulsar#3715 apache/pulsar#4526
*Motivation*
Fixes #1970
By default bookie uses a random generator to generate a bookie index as the
sticky
read bookie index. However the random generator will generate negative
numbers. Hence
it will generate negative bookie indexes in write set and cause
ArrayIndexOutOfBoundException
when bookkeeper attempts to read entries.
*Modifications*
Make sure getStickyReadBookieIndex not return negative number.
*Verify this change*
This problem introduced by a random generator. It is very hard to write a
unit test to reproduce this issue.
Existing StickyRead tests are good to cover this code change.
Reviewers: Enrico Olivelli <[email protected]>, Jia Zhai
<[email protected]>, Yong Zhang <[email protected]>
This closes #2111 from sijie/fix_sticky_read, closes #1970
---
.../org/apache/bookkeeper/client/EnsemblePlacementPolicy.java | 5 +++--
.../src/main/java/org/apache/bookkeeper/client/LedgerHandle.java | 8 +++++---
2 files changed, 8 insertions(+), 5 deletions(-)
diff --git
a/bookkeeper-server/src/main/java/org/apache/bookkeeper/client/EnsemblePlacementPolicy.java
b/bookkeeper-server/src/main/java/org/apache/bookkeeper/client/EnsemblePlacementPolicy.java
index fad3f92..7bdfb3e 100644
---
a/bookkeeper-server/src/main/java/org/apache/bookkeeper/client/EnsemblePlacementPolicy.java
+++
b/bookkeeper-server/src/main/java/org/apache/bookkeeper/client/EnsemblePlacementPolicy.java
@@ -30,6 +30,7 @@ import
org.apache.bookkeeper.client.DistributionSchedule.WriteSet;
import org.apache.bookkeeper.client.api.LedgerMetadata;
import org.apache.bookkeeper.common.annotation.InterfaceAudience;
import org.apache.bookkeeper.common.annotation.InterfaceStability;
+import org.apache.bookkeeper.common.util.MathUtils;
import org.apache.bookkeeper.conf.ClientConfiguration;
import org.apache.bookkeeper.feature.FeatureProvider;
import org.apache.bookkeeper.net.BookieSocketAddress;
@@ -378,12 +379,12 @@ public interface EnsemblePlacementPolicy {
if (!currentStickyBookieIndex.isPresent()) {
// Pick one bookie randomly from the current ensemble as the
initial
// "sticky bookie"
- return ThreadLocalRandom.current().nextInt() %
metadata.getEnsembleSize();
+ return
ThreadLocalRandom.current().nextInt(metadata.getEnsembleSize());
} else {
// When choosing a new sticky bookie index (eg: after the current
// one has read failures), by default we pick the next one in the
// ensemble, to avoid picking up the same one again.
- return (currentStickyBookieIndex.get() + 1) %
metadata.getEnsembleSize();
+ return MathUtils.signSafeMod(currentStickyBookieIndex.get() + 1,
metadata.getEnsembleSize());
}
}
diff --git
a/bookkeeper-server/src/main/java/org/apache/bookkeeper/client/LedgerHandle.java
b/bookkeeper-server/src/main/java/org/apache/bookkeeper/client/LedgerHandle.java
index 7e21f97..f3abef8 100644
---
a/bookkeeper-server/src/main/java/org/apache/bookkeeper/client/LedgerHandle.java
+++
b/bookkeeper-server/src/main/java/org/apache/bookkeeper/client/LedgerHandle.java
@@ -95,6 +95,8 @@ import org.slf4j.LoggerFactory;
public class LedgerHandle implements WriteHandle {
static final Logger LOG = LoggerFactory.getLogger(LedgerHandle.class);
+ private static final int STICKY_READ_BOOKIE_INDEX_UNSET = -1;
+
final ClientContext clientCtx;
final byte[] ledgerKey;
@@ -199,7 +201,7 @@ public class LedgerHandle implements WriteHandle {
&& getLedgerMetadata().getEnsembleSize() ==
getLedgerMetadata().getWriteQuorumSize()) {
stickyBookieIndex =
clientCtx.getPlacementPolicy().getStickyReadBookieIndex(metadata,
Optional.empty());
} else {
- stickyBookieIndex = -1;
+ stickyBookieIndex = STICKY_READ_BOOKIE_INDEX_UNSET;
}
if (clientCtx.getConf().throttleValue > 0) {
@@ -265,7 +267,7 @@ public class LedgerHandle implements WriteHandle {
// If sticky bookie reads are enabled, switch the sticky bookie to the
// next bookie in the ensemble so that we avoid to keep reading from
the
// same failed bookie
- if (stickyBookieIndex != -1) {
+ if (stickyBookieIndex != STICKY_READ_BOOKIE_INDEX_UNSET) {
// This will be idempotent when we have multiple read errors on the
// same bookie. The net result is that we just go to the next
bookie
stickyBookieIndex =
clientCtx.getPlacementPolicy().getStickyReadBookieIndex(getLedgerMetadata(),
@@ -2020,7 +2022,7 @@ public class LedgerHandle implements WriteHandle {
* This will include all bookies that are cotna
*/
WriteSet getWriteSetForReadOperation(long entryId) {
- if (stickyBookieIndex != -1) {
+ if (stickyBookieIndex != STICKY_READ_BOOKIE_INDEX_UNSET) {
// When sticky reads are enabled we want to make sure to take
// advantage of read-ahead (or, anyway, from efficiencies in
// reading sequential data from disk through the page cache).