Return-Path: X-Original-To: archive-asf-public-internal@cust-asf2.ponee.io Delivered-To: archive-asf-public-internal@cust-asf2.ponee.io Received: from cust-asf.ponee.io (cust-asf.ponee.io [163.172.22.183]) by cust-asf2.ponee.io (Postfix) with ESMTP id F1506200B5C for ; Wed, 27 Jul 2016 14:06:32 +0200 (CEST) Received: by cust-asf.ponee.io (Postfix) id EFEAB160A6E; Wed, 27 Jul 2016 12:06:32 +0000 (UTC) Delivered-To: archive-asf-public@cust-asf.ponee.io Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by cust-asf.ponee.io (Postfix) with SMTP id AE330160AA9 for ; Wed, 27 Jul 2016 14:06:31 +0200 (CEST) Received: (qmail 55596 invoked by uid 500); 27 Jul 2016 12:06:30 -0000 Mailing-List: contact commits-help@jena.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@jena.apache.org Delivered-To: mailing list commits@jena.apache.org Received: (qmail 55445 invoked by uid 99); 27 Jul 2016 12:06:30 -0000 Received: from git1-us-west.apache.org (HELO git1-us-west.apache.org) (140.211.11.23) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 27 Jul 2016 12:06:30 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id A4AACE7DE1; Wed, 27 Jul 2016 12:06:30 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: andy@apache.org To: commits@jena.apache.org Date: Wed, 27 Jul 2016 12:06:36 -0000 Message-Id: <68def92be3764ed594f5e5d7c37c15dd@git.apache.org> In-Reply-To: <81cba318e26542408405e26fd93d0334@git.apache.org> References: <81cba318e26542408405e26fd93d0334@git.apache.org> X-Mailer: ASF-Git Admin Mailer Subject: [07/11] jena git commit: Draft for testing cancellable sort()s. archived-at: Wed, 27 Jul 2016 12:06:33 -0000 Draft for testing cancellable sort()s. The overall idea is to set up a query iterator that delivers some bunch of values but after only a few (== 1) values have been pulled the iterator is cancelled; we then show that no more values can be pulled from the iterator and that the sort has been abandoned. This is a draft. Project: http://git-wip-us.apache.org/repos/asf/jena/repo Commit: http://git-wip-us.apache.org/repos/asf/jena/commit/512b2a5e Tree: http://git-wip-us.apache.org/repos/asf/jena/tree/512b2a5e Diff: http://git-wip-us.apache.org/repos/asf/jena/diff/512b2a5e Branch: refs/heads/master Commit: 512b2a5e0e470732b8e3405c124df61d91a7cfab Parents: a3f3fdc Author: chris dollin Authored: Fri Jul 22 16:10:07 2016 +0100 Committer: chris dollin Committed: Fri Jul 22 16:10:07 2016 +0100 ---------------------------------------------------------------------- .../apache/jena/atlas/data/SortedDataBag.java | 17 +- .../iterator/TestSortedDataBagCancellation.java | 244 +++++++++++++++++++ 2 files changed, 257 insertions(+), 4 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/jena/blob/512b2a5e/jena-arq/src/main/java/org/apache/jena/atlas/data/SortedDataBag.java ---------------------------------------------------------------------- diff --git a/jena-arq/src/main/java/org/apache/jena/atlas/data/SortedDataBag.java b/jena-arq/src/main/java/org/apache/jena/atlas/data/SortedDataBag.java index b248006..b7c74ae 100644 --- a/jena-arq/src/main/java/org/apache/jena/atlas/data/SortedDataBag.java +++ b/jena-arq/src/main/java/org/apache/jena/atlas/data/SortedDataBag.java @@ -83,14 +83,23 @@ public class SortedDataBag extends AbstractDataBag this.comparator = new AbortableComparator(comparator); } - /** - cancel arranges that further comparisons using the supplied - comparator will abandon the sort in progress. - */ + /** + cancel arranges that further comparisons using the supplied + comparator will abandon the sort in progress. + */ public void cancel() { comparator.cancel(); } + + /** + isCancelled is true iff cancel has been called on this + bags comparator. (Used in testing.) + */ + public boolean isCancelled() + { + return comparator.cancelled; + } protected void checkClosed() { http://git-wip-us.apache.org/repos/asf/jena/blob/512b2a5e/jena-arq/src/test/java/org/apache/jena/sparql/engine/iterator/TestSortedDataBagCancellation.java ---------------------------------------------------------------------- diff --git a/jena-arq/src/test/java/org/apache/jena/sparql/engine/iterator/TestSortedDataBagCancellation.java b/jena-arq/src/test/java/org/apache/jena/sparql/engine/iterator/TestSortedDataBagCancellation.java new file mode 100644 index 0000000..c29552e --- /dev/null +++ b/jena-arq/src/test/java/org/apache/jena/sparql/engine/iterator/TestSortedDataBagCancellation.java @@ -0,0 +1,244 @@ +/* + * 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 org.apache.jena.sparql.engine.iterator; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.apache.jena.atlas.io.IndentedWriter; +import org.apache.jena.graph.Graph; +import org.apache.jena.graph.NodeFactory; +import org.apache.jena.query.QueryCancelledException; +import org.apache.jena.query.SortCondition; +import org.apache.jena.sparql.core.DatasetGraph; +import org.apache.jena.sparql.core.DatasetGraphFactory; +import org.apache.jena.sparql.core.Var; +import org.apache.jena.sparql.engine.ExecutionContext; +import org.apache.jena.sparql.engine.binding.Binding; +import org.apache.jena.sparql.engine.binding.BindingComparator; +import org.apache.jena.sparql.engine.binding.BindingFactory; +import org.apache.jena.sparql.engine.binding.BindingMap; +import org.apache.jena.sparql.engine.iterator.QueryIterSort; +import org.apache.jena.sparql.engine.iterator.QueryIteratorBase; +import org.apache.jena.sparql.engine.main.OpExecutor; +import org.apache.jena.sparql.engine.main.OpExecutorFactory; +import org.apache.jena.sparql.graph.GraphMemPlain; +import org.apache.jena.sparql.serializer.SerializationContext; +import org.apache.jena.sparql.util.Context; +import org.junit.Test; + +import junit.framework.TestCase; + +/* + Test that a SortedDataBag used inside a QueryIterSort + does indeed cut off when cancelled. + + This is horribly clunky because of the effort of + setting up. Maybe we should instead be content to + test the SortedDataBag correctly? + +*/ +public class TestSortedDataBagCancellation extends TestCase +{ + + static final BindingMap b1 = BindingFactory.create(); + static final BindingMap b2 = BindingFactory.create(); + static final BindingMap b3 = BindingFactory.create(); + static final BindingMap b4 = BindingFactory.create(); + + static + { + b1.add(Var.alloc("v1"), NodeFactory.createLiteral("alpha")); + b2.add(Var.alloc("v2"), NodeFactory.createLiteral("beta")); + b3.add(Var.alloc("v3"), NodeFactory.createLiteral("gamma")); + b4.add(Var.alloc("v4"), NodeFactory.createLiteral("delta")); + } + + final Context params = new Context(); + + final OpExecutorFactory factory = new OpExecutorFactory() { + + @Override public OpExecutor create(ExecutionContext ec) { + throw new UnsupportedOperationException(); + } + }; + + final Graph activeGraph = new GraphMemPlain(); + + final DatasetGraph dataset = DatasetGraphFactory.create(); + + final List conditions = new ArrayList(); + + final ExecutionContext ec = new ExecutionContext + ( + params, + activeGraph, + dataset, + factory + ); + + final BindingComparator base_bc = new BindingComparator(conditions, ec); + final SpecialBindingComparator bc = new SpecialBindingComparator(base_bc, ec); + + QueryIteratorItems baseIter = new QueryIteratorItems(); + + { + baseIter.bindings.add(b1); + baseIter.bindings.add(b2); + baseIter.bindings.add(b3); + baseIter.bindings.add(b4);; + } + + QueryIterSort qs = new QueryIterSort(baseIter, bc, ec); + + /** + In this test, the iterator is not cancelled; + all items should be delivered, and the compare + count should be monotonic-nondecreasing. + */ + @Test public void testIteratesToCompletion() + { + int count = 0; + assertEquals(0, count = bc.count); + Set results = new HashSet(); + + assertTrue(qs.hasNext()); + assertTrue(bc.count >= count); count = bc.count; + results.add(qs.next()); + + assertTrue(qs.hasNext()); + assertTrue(bc.count >= count); count = bc.count; + results.add(qs.next()); + + assertTrue(qs.hasNext()); + assertTrue(bc.count >= count); count = bc.count; + results.add(qs.next()); + + assertTrue(qs.hasNext()); + assertTrue(bc.count >= count); count = bc.count; + results.add(qs.next()); + + assertFalse(qs.hasNext()); + + Set expected = new HashSet(); + expected.add(b1); + expected.add(b2); + expected.add(b3); + expected.add(b4); + + assertEquals(expected, results); + } + + /** + In this test, the iterator is cancelled after + the first result is delivered. Any attempt to + run the comparator should be trapped an exception + thrown. The iterators should deliver no more values. + */ + @Test public void testIteratesWithCancellation() + { + int count = 0; + assertEquals(0, count = bc.count); + Set results = new HashSet(); + + assertTrue(qs.hasNext()); + assertTrue(bc.count >= count); count = bc.count; + results.add(qs.next()); + + qs.cancel(); + try + { + bc.noMoreCalls(); + while (qs.hasNext()) qs.next(); + } + catch (QueryCancelledException qe) + { + assertTrue(qs.db.isCancelled()); + return; + + } + fail("query was not cancelled"); + } + + /** + A QueryIterator that delivers the elements of a list of bindings. + */ + private static final class QueryIteratorItems extends QueryIteratorBase + { + List bindings = new ArrayList(); + int index = 0; + + @Override + public void output(IndentedWriter out, SerializationContext sCxt) { + out.write("a QueryIteratorItems"); + } + + @Override + protected boolean hasNextBinding() + { + return index < bindings.size(); + } + + @Override + protected Binding moveToNextBinding() + { + index += 1; + return bindings.get(index - 1); + } + + @Override + protected void closeIterator() + { + } + + @Override + protected void requestCancel() + { + } + } + + /** + A BindingComparator that wraps another BindingComparator + and counts how many times compare() is called. + */ + static class SpecialBindingComparator extends BindingComparator + { + final BindingComparator base; + int count = 0; + boolean trapCompare = false; + + public SpecialBindingComparator(BindingComparator base, ExecutionContext ec) + { + super(base.getConditions(), ec); + this.base = base; + } + + public void noMoreCalls() { + trapCompare = true; + } + + public int compare(Binding x, Binding y) + { + if (trapCompare) throw new RuntimeException("compare() no longer allowed."); + count += 1; + return base.compare(x, y); + } + } +} \ No newline at end of file