Return-Path: X-Original-To: apmail-jackrabbit-commits-archive@www.apache.org Delivered-To: apmail-jackrabbit-commits-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 9A18F7851 for ; Thu, 1 Dec 2011 13:06:02 +0000 (UTC) Received: (qmail 85070 invoked by uid 500); 1 Dec 2011 13:06:02 -0000 Delivered-To: apmail-jackrabbit-commits-archive@jackrabbit.apache.org Received: (qmail 85031 invoked by uid 500); 1 Dec 2011 13:06:02 -0000 Mailing-List: contact commits-help@jackrabbit.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@jackrabbit.apache.org Delivered-To: mailing list commits@jackrabbit.apache.org Received: (qmail 85024 invoked by uid 99); 1 Dec 2011 13:06:02 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 01 Dec 2011 13:06:02 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=5.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 01 Dec 2011 13:06:00 +0000 Received: from eris.apache.org (localhost [127.0.0.1]) by eris.apache.org (Postfix) with ESMTP id 9D9F723888EA; Thu, 1 Dec 2011 13:05:40 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r1209063 - in /jackrabbit/trunk/jackrabbit-core/src: main/java/org/apache/jackrabbit/core/query/lucene/ test/java/org/apache/jackrabbit/core/query/ test/java/org/apache/jackrabbit/core/query/lucene/ Date: Thu, 01 Dec 2011 13:05:40 -0000 To: commits@jackrabbit.apache.org From: alexparvulescu@apache.org X-Mailer: svnmailer-1.0.8-patched Message-Id: <20111201130540.9D9F723888EA@eris.apache.org> Author: alexparvulescu Date: Thu Dec 1 13:05:38 2011 New Revision: 1209063 URL: http://svn.apache.org/viewvc?rev=1209063&view=rev Log: JCR-2906 Multivalued property sorted by last/random value Added: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/query/lucene/ComparableArrayTest.java (with props) Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/SharedFieldCache.java jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/Util.java jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/query/OrderByTest.java jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/query/SQL2OrderByTest.java Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/SharedFieldCache.java URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/SharedFieldCache.java?rev=1209063&r1=1209062&r2=1209063&view=diff ============================================================================== --- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/SharedFieldCache.java (original) +++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/SharedFieldCache.java Thu Dec 1 13:05:38 2011 @@ -17,6 +17,7 @@ package org.apache.jackrabbit.core.query.lucene; import java.io.IOException; +import java.util.Arrays; import java.util.HashMap; import java.util.Map; import java.util.WeakHashMap; @@ -112,6 +113,78 @@ public class SharedFieldCache { } } + static class ComparableArray implements Comparable { + + private int offset = 0; + + private Comparable[] c = new Comparable[0]; + + public ComparableArray(Comparable item, int index) { + insert(item, index); + } + + public int compareTo(ComparableArray o) { + return Util.compare(c, o.c); + } + + /** + * testing purpose only. + * + * @return the offset + */ + int getOffset() { + return offset; + } + + public ComparableArray insert(Comparable item, int index) { + // optimize for most common scenario + if (c.length == 0) { + offset = index; + c = new Comparable[] { item }; + return this; + } + + // inside + if (index >= offset && index < offset + c.length) { + c[index - offset] = item; + return this; + } + + // before + if (index < offset) { + int relativeOffset = offset - index; + Comparable[] newC = new Comparable[relativeOffset + c.length]; + newC[0] = item; + System.arraycopy(c, 0, newC, relativeOffset, c.length); + c = newC; + offset = index; + return this; + } + + // after + if (index >= offset + c.length) { + c = Arrays.copyOf(c, index - offset + 1); + c[index - offset] = item; + return this; + } + return this; + } + + /* + * This is needed by {@link UpperCaseSortComparator} and {@link LowerCaseSortComparator} + */ + @Override + public String toString() { + if (c == null) { + return null; + } + if (c.length == 1) { + return c[0].toString(); + } + return Arrays.toString(c); + } + } + /** * Reference to the single instance of SharedFieldCache. */ @@ -152,9 +225,10 @@ public class SharedFieldCache { field = field.intern(); ValueIndex ret = lookup(reader, field, prefix); if (ret == null) { - Comparable[] retArray = new Comparable[reader.maxDoc()]; + final int maxDocs = reader.maxDoc(); + ComparableArray[] retArray = new ComparableArray[maxDocs]; int setValues = 0; - if (retArray.length > 0) { + if (maxDocs > 0) { IndexFormatVersion version = IndexFormatVersion.getVersion(reader); boolean hasPayloads = version.isAtLeast(IndexFormatVersion.V3); TermDocs termDocs; @@ -167,8 +241,6 @@ public class SharedFieldCache { termDocs = reader.termDocs(); } TermEnum termEnum = reader.terms(new Term(field, prefix)); - - char[] tmp = new char[16]; try { if (termEnum.term() == null) { throw new RuntimeException("no terms in field " + field); @@ -178,30 +250,28 @@ public class SharedFieldCache { if (term.field() != field || !term.text().startsWith(prefix)) { break; } - - // make sure term is compacted - String text = term.text(); - int len = text.length() - prefix.length(); - if (tmp.length < len) { - // grow tmp - tmp = new char[len]; - } - text.getChars(prefix.length(), text.length(), tmp, 0); - String value = new String(tmp, 0, len); - - termDocs.seek(termEnum); + final String value = termValueAsString(term, prefix); + termDocs.seek(term); while (termDocs.next()) { + int termPosition = 0; type = PropertyType.UNDEFINED; if (hasPayloads) { TermPositions termPos = (TermPositions) termDocs; - termPos.nextPosition(); + termPosition = termPos.nextPosition(); if (termPos.isPayloadAvailable()) { payload = termPos.getPayload(payload, 0); type = PropertyMetaData.fromByteArray(payload).getPropertyType(); } } setValues++; - retArray[termDocs.doc()] = getValue(value, type); + Comparable v = getValue(value, type); + int doc = termDocs.doc(); + ComparableArray ca = retArray[doc]; + if (ca == null) { + retArray[doc] = new ComparableArray(v, termPosition); + } else { + retArray[doc] = ca.insert(v, termPosition); + } } } while (termEnum.next()); } finally { @@ -217,6 +287,22 @@ public class SharedFieldCache { } /** + * Extracts the value from a given Term as a String + * + * @param term + * @param prefix + * @return string value contained in the term + */ + private static String termValueAsString(Term term, String prefix) { + // make sure term is compacted + String text = term.text(); + int length = text.length() - prefix.length(); + char[] tmp = new char[length]; + text.getChars(prefix.length(), text.length(), tmp, 0); + return new String(tmp, 0, length); + } + + /** * See if a ValueIndex object is in the cache. */ ValueIndex lookup(IndexReader reader, String field, String prefix) { Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/Util.java URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/Util.java?rev=1209063&r1=1209062&r2=1209063&view=diff ============================================================================== --- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/Util.java (original) +++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/Util.java Thu Dec 1 13:05:38 2011 @@ -236,6 +236,25 @@ public class Util { } /** + * Compares two arrays of comparables. + */ + public static int compare(Comparable[] c1, Comparable[] c2) { + if (c1 == null) { + return -1; + } + if (c2 == null) { + return 1; + } + for (int i = 0; i < c1.length && i < c2.length; i++) { + int d = compare(c1[i], c2[i]); + if (d != 0) { + return d; + } + } + return c1.length - c2.length; + } + + /** * Compares the two values. If the values have differing types, then an * attempt is made to convert the second value into the type of the first * value. Modified: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/query/OrderByTest.java URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/query/OrderByTest.java?rev=1209063&r1=1209062&r2=1209063&view=diff ============================================================================== --- jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/query/OrderByTest.java (original) +++ jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/query/OrderByTest.java Thu Dec 1 13:05:38 2011 @@ -60,6 +60,38 @@ public class OrderByTest extends Abstrac checkResult(result, 3); } + /** + * Test for JCR-2906 + */ + public void testOrderByMVP() throws RepositoryException { + Node n1 = testRootNode.addNode("node1"); + Node n2 = testRootNode.addNode("node2"); + Node n3 = testRootNode.addNode("node3"); + Node n4 = testRootNode.addNode("node4"); + Node n5 = testRootNode.addNode("node5"); + + n1.setProperty("extra", new String[] { "12345" }); + n1.setProperty("text", new String[] { "ccc" }); + + n2.setProperty("text", new String[] { "eee", "bbb" }); + n3.setProperty("text", new String[] { "aaa" }); + n4.setProperty("text", new String[] { "bbb", "aaa" }); + n5.setProperty("text", new String[] { "eee", "aaa" }); + + testRootNode.getSession().save(); + + String sql = "SELECT value FROM nt:unstructured WHERE " + + "jcr:path LIKE '" + testRoot + "/%' ORDER BY text"; + checkResultSequence(executeQuery(sql).getRows(), new Node[] { n3, n4, + n1, n5, n2 }); + + String xpath = "/" + + testRoot + + "/*[@jcr:primaryType='nt:unstructured'] order by jcr:score(), @text"; + checkResultSequence(executeQuery(xpath).getRows(), new Node[] { n3, n4, + n1, n5, n2 }); + } + public void testOrderByUpperCase() throws RepositoryException { Node n1 = testRootNode.addNode("node1"); Node n2 = testRootNode.addNode("node2"); Modified: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/query/SQL2OrderByTest.java URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/query/SQL2OrderByTest.java?rev=1209063&r1=1209062&r2=1209063&view=diff ============================================================================== --- jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/query/SQL2OrderByTest.java (original) +++ jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/query/SQL2OrderByTest.java Thu Dec 1 13:05:38 2011 @@ -73,6 +73,30 @@ public class SQL2OrderByTest extends Abs } + /** + * SQL2 Test for JCR-2906 + */ + public void testOrderByMVP() throws RepositoryException { + Node n1 = testRootNode.addNode("node1"); + Node n2 = testRootNode.addNode("node2"); + Node n3 = testRootNode.addNode("node3"); + Node n4 = testRootNode.addNode("node4"); + Node n5 = testRootNode.addNode("node5"); + + n1.setProperty("text", new String[] { "ccc" }); + n2.setProperty("text", new String[] { "eee", "bbb" }); + n3.setProperty("text", new String[] { "aaa" }); + n4.setProperty("text", new String[] { "bbb", "aaa" }); + n5.setProperty("text", new String[] { "eee", "aaa" }); + + testRootNode.getSession().save(); + + String sql = "SELECT value FROM [nt:unstructured] WHERE ISCHILDNODE([" + + testRoot + "]) ORDER BY text"; + + checkSeq(executeSQL2Query(sql), new Node[] { n3, n4, n1, n5, n2 }); + } + public void testOrderByVal() throws RepositoryException { Node n1 = testRootNode.addNode("node1"); Added: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/query/lucene/ComparableArrayTest.java URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/query/lucene/ComparableArrayTest.java?rev=1209063&view=auto ============================================================================== --- jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/query/lucene/ComparableArrayTest.java (added) +++ jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/query/lucene/ComparableArrayTest.java Thu Dec 1 13:05:38 2011 @@ -0,0 +1,53 @@ +/* + * 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.jackrabbit.core.query.lucene; + +import static junit.framework.Assert.assertEquals; + +import javax.jcr.RepositoryException; + +import org.apache.jackrabbit.core.query.lucene.SharedFieldCache.ComparableArray; +import org.junit.Test; + +public class ComparableArrayTest { + + /** + * Test for JCR-2906 to make sure the SharedFieldCache arranges the entries + * properly and keeps the internal array creation efficient. + */ + @Test + public void testInsert() throws RepositoryException { + ComparableArray ca = new ComparableArray("a", 1); + assertEquals("a", ca.toString()); + assertEquals(1, ca.getOffset()); + + // insert before + ca.insert("b", 0); + assertEquals("[b, a]", ca.toString()); + assertEquals(0, ca.getOffset()); + + // insert after + ca.insert("c", 3); + assertEquals("[b, a, null, c]", ca.toString()); + assertEquals(0, ca.getOffset()); + + // insert inside + ca.insert("d", 2); + assertEquals("[b, a, d, c]", ca.toString()); + assertEquals(0, ca.getOffset()); + } +} Propchange: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/query/lucene/ComparableArrayTest.java ------------------------------------------------------------------------------ svn:mime-type = text/plain