// Copyright 2017 JanusGraph Authors // // Licensed 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 org.janusgraph.diskstorage.keycolumnvalue; import com.google.common.base.Preconditions; import org.janusgraph.diskstorage.Entry; import org.janusgraph.diskstorage.EntryList; import org.janusgraph.diskstorage.StaticBuffer; import org.janusgraph.diskstorage.util.BufferUtil; import org.janusgraph.diskstorage.util.StaticArrayEntryList; import org.janusgraph.graphdb.query.BackendQuery; import org.janusgraph.graphdb.query.BaseQuery; import org.apache.commons.lang.builder.HashCodeBuilder; import java.util.ArrayList; import java.util.Collections; import java.util.List; /** * Queries for a slice of data identified by a start point (inclusive) and end point (exclusive). * Returns all {@link StaticBuffer}s that lie in this range up to the given limit. * <p/> * If a SliceQuery is marked <i>static</i> it is expected that the result set does not change. * * @author Matthias Broecheler (me@matthiasb.com) */ public class SliceQuery extends BaseQuery implements BackendQuery<SliceQuery> { private final StaticBuffer sliceStart; private final StaticBuffer sliceEnd; public SliceQuery(final StaticBuffer sliceStart, final StaticBuffer sliceEnd) { assert sliceStart != null && sliceEnd != null; this.sliceStart = sliceStart; this.sliceEnd = sliceEnd; } public SliceQuery(final SliceQuery query) { this(query.getSliceStart(), query.getSliceEnd()); setLimit(query.getLimit()); } /** * The start of the slice is considered to be inclusive * * @return The StaticBuffer denoting the start of the slice */ public StaticBuffer getSliceStart() { return sliceStart; } /** * The end of the slice is considered to be exclusive * * @return The StaticBuffer denoting the end of the slice */ public StaticBuffer getSliceEnd() { return sliceEnd; } @Override public int hashCode() { return new HashCodeBuilder().append(sliceStart).append(sliceEnd).append(getLimit()).toHashCode(); } @Override public boolean equals(Object other) { if (this == other) return true; if (other == null && !getClass().isInstance(other)) return false; SliceQuery oth = (SliceQuery) other; return sliceStart.equals(oth.sliceStart) && sliceEnd.equals(oth.sliceEnd) && getLimit() == oth.getLimit(); } public boolean subsumes(SliceQuery oth) { Preconditions.checkNotNull(oth); if (this == oth) return true; if (oth.getLimit() > getLimit()) return false; else if (!hasLimit()) //the interval must be subsumed return sliceStart.compareTo(oth.sliceStart) <= 0 && sliceEnd.compareTo(oth.sliceEnd) >= 0; else //this the result might be cutoff due to limit, the start must be the same return sliceStart.compareTo(oth.sliceStart) == 0 && sliceEnd.compareTo(oth.sliceEnd) >= 0; } //TODO: make this more efficient by using reuseIterator() on otherResult public EntryList getSubset(final SliceQuery otherQuery, final EntryList otherResult) { assert otherQuery.subsumes(this); int pos = Collections.binarySearch(otherResult, sliceStart); if (pos < 0) pos = -pos - 1; List<Entry> result = new ArrayList<Entry>(); for (; pos < otherResult.size() && result.size() < getLimit(); pos++) { Entry e = otherResult.get(pos); if (e.getColumnAs(StaticBuffer.STATIC_FACTORY).compareTo(sliceEnd) < 0) result.add(e); else break; } return StaticArrayEntryList.of(result); } public boolean contains(StaticBuffer buffer) { return sliceStart.compareTo(buffer)<=0 && sliceEnd.compareTo(buffer)>0; } public static StaticBuffer pointRange(StaticBuffer point) { return BufferUtil.nextBiggerBuffer(point); } @Override public SliceQuery setLimit(int limit) { Preconditions.checkArgument(!hasLimit()); super.setLimit(limit); return this; } @Override public SliceQuery updateLimit(int newLimit) { return new SliceQuery(sliceStart, sliceEnd).setLimit(newLimit); } }