Skip to content

Commit 898d08a

Browse files
committed
NextPage returns the exact minCzxid and offset
1 parent c400bc1 commit 898d08a

File tree

4 files changed

+152
-39
lines changed

4 files changed

+152
-39
lines changed

zookeeper-server/src/main/java/org/apache/zookeeper/ZooDefs.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,7 @@ public interface AddWatchModes {
164164
@InterfaceAudience.Public
165165
public interface GetChildrenPaginated {
166166
long lastPageMinCzxid = -1L;
167+
int lastPageCzxidOffset = -1;
167168
}
168169

169170
public static final String[] opNames = {"notification", "create", "delete", "exists", "getData", "setData", "getACL", "setACL", "getChildren", "getChildren2", "getMaxChildren", "setMaxChildren", "ping", "reconfig", "getConfig"};

zookeeper-server/src/main/java/org/apache/zookeeper/ZooKeeper.java

Lines changed: 36 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2781,9 +2781,14 @@ public List<String> getChildren(final String path, Watcher watcher) throws Keepe
27812781
* @param outputNextPage
27822782
* - if not null, {@link PaginationNextPage} info returned from server will be copied to
27832783
* {@code outputNextPage}. The info can be used for fetching the next page of remaining children,
2784-
* or checking whether the returned page is the last page.
2784+
* or checking whether the returned page is the last page by comparing
2785+
* {@link PaginationNextPage#getMinCzxid()} with
2786+
* {@link org.apache.zookeeper.ZooDefs.GetChildrenPaginated#lastPageMinCzxid}
27852787
* @return
2786-
* a list of children nodes, up to {@code maxReturned}
2788+
* a list of children nodes, up to {@code maxReturned}.
2789+
* <p>When params are set {@code maxReturned} = {@code Integer.MAX_VALUE}, {@code minCzxid} <= 0:
2790+
* the children list is unordered if all the children can be returned in a page;
2791+
* <p>Otherwise, the children list is ordered by czxid.
27872792
* @throws KeeperException
27882793
* if the server signals an error with a non-zero error code.
27892794
* @throws IllegalArgumentException
@@ -2860,7 +2865,7 @@ public List<String> getChildren(final String path,
28602865
*
28612866
* @param path the path of the parent node
28622867
* @param watch whether or not leave a watch on the given node
2863-
* @return a list of all children of the given path
2868+
* @return a unordered list of all children of the given path
28642869
* @throws KeeperException if the server signals an error with a non-zero error code.
28652870
* @throws InterruptedException if the server transaction is interrupted.
28662871
*/
@@ -2874,21 +2879,39 @@ public List<String> getAllChildrenPaginated(String path, boolean watch)
28742879
}
28752880

28762881
Set<String> childrenSet = new HashSet<>(childrenPaginated);
2882+
getChildrenRemainingPages(path, watcher, nextPage, childrenSet);
2883+
2884+
return new ArrayList<>(childrenSet);
2885+
}
2886+
2887+
private void getChildrenRemainingPages(String path,
2888+
Watcher watcher,
2889+
PaginationNextPage nextPage,
2890+
Set<String> childrenSet) throws KeeperException, InterruptedException {
2891+
int retryCount = 0;
28772892
do {
2893+
List<String> childrenPaginated;
28782894
long minCzxid = nextPage.getMinCzxid();
2879-
// If a child with the same czxid is returned in the previous page, and then deleted
2880-
// on the server, the children not in the previous page but offset is less than czxidOffset
2881-
// would be missed in the next page. Use the last child in the previous page to determine whether or not
2882-
// the deletion case happens. If it happens, retry fetching the page starting from offset 0.
2883-
int czxidOffset = nextPage.getMinCzxidOffset() - 1;
2884-
childrenPaginated = getChildren(path, watcher, Integer.MAX_VALUE, minCzxid, czxidOffset, null, nextPage);
2885-
if (!childrenPaginated.isEmpty() && !childrenSet.contains(childrenPaginated.get(0))) {
2886-
childrenPaginated = getChildren(path, watcher, Integer.MAX_VALUE, minCzxid, 0, null, nextPage);
2895+
if (nextPage.getMinCzxidOffset() == 0) {
2896+
childrenPaginated = getChildren(path, watcher, Integer.MAX_VALUE, minCzxid,
2897+
nextPage.getMinCzxidOffset(), null, nextPage);
2898+
} else {
2899+
// If a child with the same czxid is returned in the previous page, and then deleted
2900+
// on the server, the children not in the previous page but offset is less than czxidOffset
2901+
// would be missed in the next page. Use the last child in the previous page to determine whether or not
2902+
// the deletion case happens. If it happens, retry fetching the page starting from offset 0.
2903+
childrenPaginated = getChildren(path, watcher, Integer.MAX_VALUE, minCzxid,
2904+
nextPage.getMinCzxidOffset() - 1, null, nextPage);
2905+
if (!childrenPaginated.isEmpty() && !childrenSet.contains(childrenPaginated.get(0))) {
2906+
if (retryCount++ >= 3) {
2907+
throw KeeperException.create(Code.OPERATIONTIMEOUT);
2908+
}
2909+
LOG.info("Retry fetching children for minZxid = {}, retries = {}", minCzxid, retryCount);
2910+
childrenPaginated = getChildren(path, watcher, Integer.MAX_VALUE, minCzxid, 0, null, nextPage);
2911+
}
28872912
}
28882913
childrenSet.addAll(childrenPaginated);
28892914
} while (nextPage.getMinCzxid() != ZooDefs.GetChildrenPaginated.lastPageMinCzxid);
2890-
2891-
return new ArrayList<>(childrenSet);
28922915
}
28932916

28942917
private void updateNextPage(PaginationNextPage nextPage, long minCzxId, int czxIdOffset) {

zookeeper-server/src/main/java/org/apache/zookeeper/server/DataTree.java

Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -878,18 +878,25 @@ public List<String> getPaginatedChildren(String path, Stat stat, Watcher watcher
878878
updateReadStat(path, countReadChildrenBytes(allChildren));
879879
if (outputNextPage != null) {
880880
outputNextPage.setMinCzxid(ZooDefs.GetChildrenPaginated.lastPageMinCzxid);
881+
outputNextPage.setMinCzxidOffset(ZooDefs.GetChildrenPaginated.lastPageCzxidOffset);
881882
}
882883
return allChildren;
883884
}
884885
}
885886

887+
return getSortedPaginatedChildren(n, path, stat, watcher, maxReturned, minCzxId, czxIdOffset, outputNextPage);
888+
}
889+
890+
private List<String> getSortedPaginatedChildren(DataNode node, String path, Stat stat, Watcher watcher,
891+
int maxReturned, long minCzxId, int czxIdOffset,
892+
PaginationNextPage outputNextPage) {
886893
int index = 0;
887894
List<PathWithStat> targetChildren = new ArrayList<PathWithStat>();
888895
List<String> paginatedChildren = new ArrayList<String>();
889896

890897
// Need to lock the parent node for the whole block between reading children list and adding watch
891-
synchronized (n) {
892-
buildChildrenPathWithStat(n, path, stat, minCzxId, targetChildren);
898+
synchronized (node) {
899+
buildChildrenPathWithStat(node, path, stat, minCzxId, targetChildren);
893900

894901
targetChildren.sort(staticNodeCreationComparator);
895902

@@ -981,22 +988,30 @@ private void updateNextPage(PaginationNextPage nextPage, List<PathWithStat> chil
981988
if (lastAddedIndex == children.size() - 1) {
982989
// All children are added, so this is the last page
983990
nextPage.setMinCzxid(ZooDefs.GetChildrenPaginated.lastPageMinCzxid);
991+
nextPage.setMinCzxidOffset(ZooDefs.GetChildrenPaginated.lastPageCzxidOffset);
984992
return;
985993
}
986994

987-
// Find the minCzxidOffset next next page by searching the index (startIndex) of czxid
988-
// that is not equal to current czxid.
989-
// minCzxidOffset of next page = lastAddedIndex - startIndex
990995
long lastCzxid = children.get(lastAddedIndex).getStat().getCzxid();
991-
int startIndex = lastAddedIndex;
992-
while (startIndex >= 0) {
993-
if (children.get(startIndex).getStat().getCzxid() != lastCzxid) {
994-
break;
996+
long nextCzxid = children.get(lastAddedIndex + 1).getStat().getCzxid();
997+
int nextCzixdOffset = 0;
998+
999+
if (nextCzxid == lastCzxid) {
1000+
// Find the minCzxidOffset next next page by searching the index (startIndex) of czxid
1001+
// that is not equal to current czxid.
1002+
// minCzxidOffset of next page = lastAddedIndex - startIndex
1003+
int startIndex = lastAddedIndex;
1004+
while (startIndex >= 0) {
1005+
if (children.get(startIndex).getStat().getCzxid() != lastCzxid) {
1006+
break;
1007+
}
1008+
startIndex--;
9951009
}
996-
startIndex--;
1010+
nextCzixdOffset = lastAddedIndex - startIndex;
9971011
}
998-
nextPage.setMinCzxid(lastCzxid);
999-
nextPage.setMinCzxidOffset(lastAddedIndex - startIndex);
1012+
1013+
nextPage.setMinCzxid(nextCzxid);
1014+
nextPage.setMinCzxidOffset(nextCzixdOffset);
10001015
}
10011016

10021017
public Stat setACL(String path, List<ACL> acl, int version) throws KeeperException.NoNodeException {

0 commit comments

Comments
 (0)