Skip to content
Permalink
Browse files
Fix remaining count error when query edge in page (#515)
Change-Id: I07920cb7de15a837cfad1f0a130fc6d036e4d3bd
  • Loading branch information
Linary authored and zhoney committed May 22, 2019
1 parent 387cef5 commit 7def8302d60a3f26f10966c3cc3b127ef6c6bb48
Showing 20 changed files with 232 additions and 207 deletions.
@@ -33,7 +33,7 @@

import com.baidu.hugegraph.HugeException;
import com.baidu.hugegraph.api.API;
import com.baidu.hugegraph.backend.page.PageState;
import com.baidu.hugegraph.backend.page.PageInfo;
import com.baidu.hugegraph.iterator.Metadatable;
import com.baidu.hugegraph.schema.EdgeLabel;
import com.baidu.hugegraph.schema.IndexLabel;
@@ -101,7 +101,7 @@ private String writeIterator(String label, Iterator<?> iter,
if (iter instanceof GraphTraversal<?, ?>) {
page = TraversalUtil.page((GraphTraversal<?, ?>) iter);
} else if (iter instanceof Metadatable) {
page = PageState.page(iter);
page = PageInfo.page(iter);
} else {
throw new HugeException("Invalid paging iterator: %s",
iter.getClass());
@@ -22,6 +22,7 @@
import java.util.Iterator;
import java.util.function.BiFunction;

import com.baidu.hugegraph.backend.page.PageState;
import com.baidu.hugegraph.backend.query.Query;
import com.baidu.hugegraph.backend.store.BackendEntry;
import com.baidu.hugegraph.backend.store.BackendEntryIterator;
@@ -115,6 +116,7 @@ protected String pageState() {
if (page == null || this.results.isExhausted()) {
return null;
}
return page.toString();
byte[] position = page.toBytes();
return new PageState(position, 0, (int) this.count()).toString();
}
}
@@ -31,6 +31,7 @@

import com.baidu.hugegraph.backend.BackendException;
import com.baidu.hugegraph.backend.id.Id;
import com.baidu.hugegraph.backend.page.PageState;
import com.baidu.hugegraph.backend.query.Condition;
import com.baidu.hugegraph.backend.query.Condition.Relation;
import com.baidu.hugegraph.backend.query.Query;
@@ -168,8 +169,9 @@ protected void setPageState(Query query, List<Select> selects) {
select.setFetchSize((int) total);
// It's the first time if page is empty
if (!page.isEmpty()) {
byte[] position = PageState.fromString(page).position();
try {
select.setPagingState(PagingState.fromString(page));
select.setPagingState(PagingState.fromBytes(position));
} catch (PagingStateException e) {
throw new BackendException(e);
}
@@ -33,24 +33,24 @@ public class PageEntryIterator implements Iterator<BackendEntry>, Metadatable {
private final QueryList queries;
private final long pageSize;
private QueryList.PageIterator results;
private PageState pageState;
private PageInfo pageInfo;
private long remaining;

public PageEntryIterator(QueryList queries, long pageSize) {
this.queries = queries;
this.pageSize = pageSize;
this.results = QueryList.PageIterator.EMPTY;
this.pageState = this.parsePageState();
this.pageInfo = this.parsePageState();
this.remaining = queries.parent().limit();
}

private PageState parsePageState() {
private PageInfo parsePageState() {
String page = this.queries.parent().pageWithoutCheck();
PageState pageState = PageState.fromString(page);
E.checkState(pageState.offset() < this.queries.total(),
PageInfo pageInfo = PageInfo.fromString(page);
E.checkState(pageInfo.offset() < this.queries.total(),
"Invalid page '%s' with an offset '%s' exceeds " +
"the size of IdHolderList", page, pageState.offset());
return pageState;
"the size of IdHolderList", page, pageInfo.offset());
return pageInfo;
}

@Override
@@ -63,26 +63,27 @@ public boolean hasNext() {

private boolean fetch() {
if ((this.remaining != Query.NO_LIMIT && this.remaining <= 0L) ||
this.pageState.offset() >= this.queries.total()) {
this.pageInfo.offset() >= this.queries.total()) {
return false;
}

long pageSize = this.pageSize;
if (this.remaining != Query.NO_LIMIT && this.remaining < pageSize) {
pageSize = this.remaining;
}
this.results = this.queries.fetchNext(this.pageState, pageSize);
this.results = this.queries.fetchNext(this.pageInfo, pageSize);
assert this.results != null;

if (this.results.iterator().hasNext()) {
if (this.results.page() == null) {
this.pageState.increase();
this.pageInfo.increase();
} else {
this.pageState.page(this.results.page());
this.pageInfo.page(this.results.page());
this.remaining -= this.results.total();
}
return true;
} else {
this.pageState.increase();
this.pageInfo.increase();
return this.fetch();
}
}
@@ -92,21 +93,16 @@ public BackendEntry next() {
if (!this.hasNext()) {
throw new NoSuchElementException();
}
BackendEntry entry = this.results.iterator().next();
if (this.remaining != Query.NO_LIMIT) {
// Assume one result in each entry (just for index query)
this.remaining--;
}
return entry;
return this.results.iterator().next();
}

@Override
public Object metadata(String meta, Object... args) {
if (PageState.PAGE.equals(meta)) {
if (this.pageState.offset() >= this.queries.total()) {
if (PageInfo.PAGE.equals(meta)) {
if (this.pageInfo.offset() >= this.queries.total()) {
return null;
}
return this.pageState.toString();
return this.pageInfo.toString();
}
throw new NotSupportException("Invalid meta '%s'", meta);
}
@@ -0,0 +1,110 @@
/*
* Copyright 2017 HugeGraph Authors
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/

package com.baidu.hugegraph.backend.page;

import java.util.Base64;
import java.util.Iterator;

import com.baidu.hugegraph.HugeException;
import com.baidu.hugegraph.backend.serializer.BytesBuffer;
import com.baidu.hugegraph.iterator.Metadatable;
import com.baidu.hugegraph.util.Bytes;
import com.baidu.hugegraph.util.E;

public final class PageInfo {

public static final String PAGE = "page";
public static final String PAGE_NONE = "";

private int offset;
private String page;

public PageInfo(int offset, String page) {
E.checkArgument(offset >= 0, "The offset must be >= 0");
E.checkNotNull(page, "page");
this.offset = offset;
this.page = page;
}

public void increase() {
this.offset++;
this.page = PAGE_NONE;
}

public int offset() {
return this.offset;
}

public void page(String page) {
this.page = page;
}

public String page() {
return this.page;
}

@Override
public String toString() {
return Base64.getEncoder().encodeToString(this.toBytes());
}

public byte[] toBytes() {
byte[] pageState = PageState.toBytes(this.page);
int length = 2 + BytesBuffer.INT_LEN + pageState.length;
BytesBuffer buffer = BytesBuffer.allocate(length);
buffer.writeInt(this.offset);
buffer.writeBytes(pageState);
return buffer.bytes();
}

public static PageInfo fromString(String page) {
byte[] bytes;
try {
bytes = Base64.getDecoder().decode(page);
} catch (Exception e) {
throw new HugeException("Invalid page: '%s'", e, page);
}
return fromBytes(bytes);
}

public static PageInfo fromBytes(byte[] bytes) {
if (bytes.length == 0) {
// The first page
return new PageInfo(0, PAGE_NONE);
}
try {
BytesBuffer buffer = BytesBuffer.wrap(bytes);
int offset = buffer.readInt();
byte[] pageState = buffer.readBytes();
String page = PageState.toString(pageState);
return new PageInfo(offset, page);
} catch (Exception e) {
throw new HugeException("Invalid page: '0x%s'",
e, Bytes.toHex(bytes));
}
}

public static String page(Iterator<?> iterator) {
E.checkState(iterator instanceof Metadatable,
"Invalid paging iterator: %s", iterator.getClass());
Object page = ((Metadatable) iterator).metadata(PAGE);
return (String) page;
}
}

0 comments on commit 7def830

Please sign in to comment.