Return-Path: Delivered-To: apmail-lucene-java-commits-archive@www.apache.org Received: (qmail 75634 invoked from network); 31 Mar 2009 15:41:39 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (140.211.11.3) by minotaur.apache.org with SMTP; 31 Mar 2009 15:41:39 -0000 Received: (qmail 73930 invoked by uid 500); 31 Mar 2009 15:41:38 -0000 Delivered-To: apmail-lucene-java-commits-archive@lucene.apache.org Received: (qmail 73893 invoked by uid 500); 31 Mar 2009 15:41:38 -0000 Mailing-List: contact java-commits-help@lucene.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: java-dev@lucene.apache.org Delivered-To: mailing list java-commits@lucene.apache.org Received: (qmail 73884 invoked by uid 99); 31 Mar 2009 15:41:37 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 31 Mar 2009 15:41:37 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=10.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; Tue, 31 Mar 2009 15:41:30 +0000 Received: by eris.apache.org (Postfix, from userid 65534) id AFD2F2388962; Tue, 31 Mar 2009 15:41:10 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r760486 - in /lucene/java/trunk/src: java/org/apache/lucene/index/IndexReader.java java/org/apache/lucene/index/SegmentReader.java java/org/apache/lucene/search/FieldCacheImpl.java test/org/apache/lucene/index/TestIndexReader.java Date: Tue, 31 Mar 2009 15:41:09 -0000 To: java-commits@lucene.apache.org From: mikemccand@apache.org X-Mailer: svnmailer-1.0.8 Message-Id: <20090331154110.AFD2F2388962@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org Author: mikemccand Date: Tue Mar 31 15:41:08 2009 New Revision: 760486 URL: http://svn.apache.org/viewvc?rev=760486&view=rev Log: LUCENE-1579: make sure cloned SegmentReaders share the same entry in FieldCache Modified: lucene/java/trunk/src/java/org/apache/lucene/index/IndexReader.java lucene/java/trunk/src/java/org/apache/lucene/index/SegmentReader.java lucene/java/trunk/src/java/org/apache/lucene/search/FieldCacheImpl.java lucene/java/trunk/src/test/org/apache/lucene/index/TestIndexReader.java Modified: lucene/java/trunk/src/java/org/apache/lucene/index/IndexReader.java URL: http://svn.apache.org/viewvc/lucene/java/trunk/src/java/org/apache/lucene/index/IndexReader.java?rev=760486&r1=760485&r2=760486&view=diff ============================================================================== --- lucene/java/trunk/src/java/org/apache/lucene/index/IndexReader.java (original) +++ lucene/java/trunk/src/java/org/apache/lucene/index/IndexReader.java Tue Mar 31 15:41:08 2009 @@ -1248,4 +1248,10 @@ public IndexReader[] getSequentialSubReaders() { return null; } + + /** Expert + * @deprecated */ + public Object getFieldCacheKey() { + return this; + } } Modified: lucene/java/trunk/src/java/org/apache/lucene/index/SegmentReader.java URL: http://svn.apache.org/viewvc/lucene/java/trunk/src/java/org/apache/lucene/index/SegmentReader.java?rev=760486&r1=760485&r2=760486&view=diff ============================================================================== --- lucene/java/trunk/src/java/org/apache/lucene/index/SegmentReader.java (original) +++ lucene/java/trunk/src/java/org/apache/lucene/index/SegmentReader.java Tue Mar 31 15:41:08 2009 @@ -1250,4 +1250,11 @@ norm.dirty = norm.rollbackDirty; } } + + // This is necessary so that cloned SegmentReaders (which + // share the underlying postings data) will map to the + // same entry in the FieldCache. See LUCENE-1579. + public final Object getFieldCacheKey() { + return freqStream; + } } Modified: lucene/java/trunk/src/java/org/apache/lucene/search/FieldCacheImpl.java URL: http://svn.apache.org/viewvc/lucene/java/trunk/src/java/org/apache/lucene/search/FieldCacheImpl.java?rev=760486&r1=760485&r2=760486&view=diff ============================================================================== --- lucene/java/trunk/src/java/org/apache/lucene/search/FieldCacheImpl.java (original) +++ lucene/java/trunk/src/java/org/apache/lucene/search/FieldCacheImpl.java Tue Mar 31 15:41:08 2009 @@ -50,11 +50,13 @@ public Object get(IndexReader reader, Object key) throws IOException { Map innerCache; Object value; + final Object readerKey = reader.getFieldCacheKey(); + synchronized (readerCache) { - innerCache = (Map) readerCache.get(reader); + innerCache = (Map) readerCache.get(readerKey); if (innerCache == null) { innerCache = new HashMap(); - readerCache.put(reader, innerCache); + readerCache.put(readerKey, innerCache); value = null; } else { value = innerCache.get(key); Modified: lucene/java/trunk/src/test/org/apache/lucene/index/TestIndexReader.java URL: http://svn.apache.org/viewvc/lucene/java/trunk/src/test/org/apache/lucene/index/TestIndexReader.java?rev=760486&r1=760485&r2=760486&view=diff ============================================================================== --- lucene/java/trunk/src/test/org/apache/lucene/index/TestIndexReader.java (original) +++ lucene/java/trunk/src/test/org/apache/lucene/index/TestIndexReader.java Tue Mar 31 15:41:08 2009 @@ -44,6 +44,7 @@ import org.apache.lucene.search.ScoreDoc; import org.apache.lucene.search.TermQuery; import org.apache.lucene.search.Query; +import org.apache.lucene.search.FieldCache; import org.apache.lucene.store.AlreadyClosedException; import org.apache.lucene.store.Directory; import org.apache.lucene.store.FSDirectory; @@ -1685,4 +1686,112 @@ s.close(); r.close(); } + + // LUCENE-1579: Ensure that on a cloned reader, segments + // reuse the doc values arrays in FieldCache + public void testFieldCacheReuseAfterClone() throws Exception { + Directory dir = new MockRAMDirectory(); + IndexWriter writer = new IndexWriter(dir, new WhitespaceAnalyzer(), IndexWriter.MaxFieldLength.UNLIMITED); + Document doc = new Document(); + doc.add(new Field("number", "17", Field.Store.NO, Field.Index.NOT_ANALYZED)); + writer.addDocument(doc); + writer.close(); + + // Open reader + IndexReader r = IndexReader.open(dir); + assertTrue(r instanceof SegmentReader); + final int[] ints = FieldCache.DEFAULT.getInts(r, "number"); + assertEquals(1, ints.length); + assertEquals(17, ints[0]); + + // Clone reader + IndexReader r2 = (IndexReader) r.clone(); + r.close(); + assertTrue(r2 != r); + assertTrue(r2 instanceof SegmentReader); + final int[] ints2 = FieldCache.DEFAULT.getInts(r2, "number"); + r2.close(); + + assertEquals(1, ints2.length); + assertEquals(17, ints2[0]); + assertTrue(ints == ints2); + + dir.close(); + } + + // LUCENE-1579: Ensure that on a reopened reader, that any + // shared segments reuse the doc values arrays in + // FieldCache + public void testFieldCacheReuseAfterReopen() throws Exception { + Directory dir = new MockRAMDirectory(); + IndexWriter writer = new IndexWriter(dir, new WhitespaceAnalyzer(), IndexWriter.MaxFieldLength.UNLIMITED); + Document doc = new Document(); + doc.add(new Field("number", "17", Field.Store.NO, Field.Index.NOT_ANALYZED)); + writer.addDocument(doc); + writer.commit(); + + // Open reader1 + IndexReader r = IndexReader.open(dir); + assertTrue(r instanceof SegmentReader); + final int[] ints = FieldCache.DEFAULT.getInts(r, "number"); + assertEquals(1, ints.length); + assertEquals(17, ints[0]); + + // Add new segment + writer.addDocument(doc); + writer.commit(); + + // Reopen reader1 --> reader2 + IndexReader r2 = (IndexReader) r.reopen(); + r.close(); + assertTrue(r2 instanceof MultiSegmentReader); + IndexReader sub0 = r2.getSequentialSubReaders()[0]; + assertTrue(sub0 instanceof SegmentReader); + final int[] ints2 = FieldCache.DEFAULT.getInts(sub0, "number"); + r2.close(); + assertTrue(ints == ints2); + + dir.close(); + } + + // LUCENE-1579: Make sure all SegmentReaders are new when + // reopen switches readOnly + public void testReopenChangeReadonly() throws Exception { + Directory dir = new MockRAMDirectory(); + IndexWriter writer = new IndexWriter(dir, new WhitespaceAnalyzer(), IndexWriter.MaxFieldLength.UNLIMITED); + Document doc = new Document(); + doc.add(new Field("number", "17", Field.Store.NO, Field.Index.NOT_ANALYZED)); + writer.addDocument(doc); + writer.commit(); + + // Open reader1 + IndexReader r = IndexReader.open(dir); + assertTrue(r instanceof SegmentReader); + final int[] ints = FieldCache.DEFAULT.getInts(r, "number"); + assertEquals(1, ints.length); + assertEquals(17, ints[0]); + + // Reopen to readonly w/ no chnages + IndexReader r3 = (IndexReader) r.reopen(true); + assertTrue(r3 instanceof ReadOnlySegmentReader); + r3.close(); + + // Add new segment + writer.addDocument(doc); + writer.commit(); + + // Reopen reader1 --> reader2 + IndexReader r2 = (IndexReader) r.reopen(true); + r.close(); + assertTrue(r2 instanceof MultiSegmentReader); + IndexReader[] subs = r2.getSequentialSubReaders(); + final int[] ints2 = FieldCache.DEFAULT.getInts(subs[0], "number"); + r2.close(); + + assertTrue(subs[0] instanceof ReadOnlySegmentReader); + assertTrue(subs[1] instanceof ReadOnlySegmentReader); + assertTrue(ints == ints2); + + dir.close(); + } }