Index: solr/core/src/test/org/apache/solr/core/TestLuceneIndexReaderFactory.java
===================================================================
--- solr/core/src/test/org/apache/solr/core/TestLuceneIndexReaderFactory.java	(revision 0)
+++ solr/core/src/test/org/apache/solr/core/TestLuceneIndexReaderFactory.java	(revision 0)
@@ -0,0 +1,129 @@
+package org.apache.solr.core;
+
+/**
+ * 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.
+ */
+
+import java.io.IOException;
+import java.util.Collection;
+import java.util.Map;
+
+import org.apache.lucene.document.Document;
+import org.apache.lucene.document.Field;
+import org.apache.lucene.document.Field.Index;
+import org.apache.lucene.document.Field.Store;
+import org.apache.lucene.index.DirectoryReader;
+import org.apache.lucene.index.IndexDeletionPolicy;
+import org.apache.lucene.index.IndexReader.ReaderFinishedListener;
+import org.apache.lucene.index.IndexWriter;
+import org.apache.lucene.index.IndexWriterConfig;
+import org.apache.lucene.index.ReadOnlyDirectoryReader;
+import org.apache.lucene.index.SegmentInfos;
+import org.apache.lucene.index.SegmentReader;
+import org.apache.lucene.store.Directory;
+import org.apache.solr.SolrTestCaseJ4;
+import org.apache.solr.update.AddUpdateCommand;
+import org.apache.solr.update.DirectUpdateHandler2;
+import org.apache.solr.util.plugin.SolrCoreAware;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+// set a custom Lucene IndexReaderFactory
+// test to see if it is correctly set in Solr
+public class TestLuceneIndexReaderFactory extends SolrTestCaseJ4 {
+  @BeforeClass
+  public static void beforeClass() throws Exception {
+    initCore("solrconfig-luceneirf.xml", "schema12.xml");
+  }
+  
+  @Test
+  public void test() throws Exception {
+    assertQ(req("q","*:*","qt","standard"));
+    DirectUpdateHandler2 uh = (DirectUpdateHandler2)h.getCore().getUpdateHandler();
+
+    AddUpdateCommand cmd = new AddUpdateCommand();
+    cmd.overwriteCommitted = true;
+    cmd.overwritePending = true;
+    cmd.allowDups = false;
+
+    cmd.doc = new Document();
+    cmd.doc.add( new Field( "id", "AAA", Store.YES, Index.NOT_ANALYZED ) );
+    cmd.doc.add( new Field( "subject", "xxxxx", Store.YES, Index.NOT_ANALYZED ) );
+    uh.addDoc( cmd );
+    
+    IndexWriter iw = uh.getWriter();
+    IndexWriterConfig iwc = iw.getConfig();
+    assertTrue(iwc.getIndexReaderFactory() instanceof TestIndexReaderFactory);
+    
+    assertTrue(TestIndexReaderFactory.core == h.getCore());
+  }
+  
+  // Just for testing
+  public static class TestIndexReaderFactory extends
+      org.apache.lucene.index.IndexReaderFactory implements SolrCoreAware {    
+    static SolrCore core;
+    
+    
+    public void inform(SolrCore core) {
+      TestIndexReaderFactory.core = core;
+    }
+    
+    @Override
+    public DirectoryReader create(IndexWriter writer, SegmentInfos infos,
+        int termInfosIndexDivisor, boolean applyAllDeletes, boolean readOnly)
+        throws IOException {
+      if (readOnly) {
+        return new ReadOnlyDirectoryReader(writer, infos,
+            termInfosIndexDivisor, applyAllDeletes);
+      } else {
+        return new DirectoryReader(writer, infos, termInfosIndexDivisor,
+            applyAllDeletes);
+      }
+    }
+    
+    @Override
+    public DirectoryReader create(Directory directory, SegmentInfos infos,
+        SegmentReader[] oldReaders, int[] oldStarts,
+        Map<String,byte[]> oldNormsCache, boolean doClone,
+        int termInfosIndexDivisor,
+        Collection<ReaderFinishedListener> readerFinishedListeners,
+        boolean readOnly) throws IOException {
+      if (readOnly) {
+        return new ReadOnlyDirectoryReader(directory, infos, oldReaders,
+            oldStarts, oldNormsCache, doClone, termInfosIndexDivisor,
+            readerFinishedListeners);
+      } else {
+        return new DirectoryReader(directory, infos, oldReaders, oldStarts,
+            oldNormsCache, readOnly, doClone, termInfosIndexDivisor,
+            readerFinishedListeners);
+      }
+    }
+    
+    @Override
+    public DirectoryReader create(Directory directory, SegmentInfos sis,
+        IndexDeletionPolicy deletionPolicy, int termInfosIndexDivisor,
+        Collection<ReaderFinishedListener> readerFinishedListeners,
+        boolean readOnly) throws IOException {
+      if (readOnly) {
+        return new ReadOnlyDirectoryReader(directory, sis, deletionPolicy,
+            termInfosIndexDivisor, readerFinishedListeners);
+      } else {
+        return new DirectoryReader(directory, sis, deletionPolicy, readOnly,
+            termInfosIndexDivisor, readerFinishedListeners);
+      }
+    }
+  }
+}
Index: solr/core/src/test/org/apache/solr/core/SolrIndexReaderFactoryTest.java
===================================================================
--- solr/core/src/test/org/apache/solr/core/SolrIndexReaderFactoryTest.java	(revision 0)
+++ solr/core/src/test/org/apache/solr/core/SolrIndexReaderFactoryTest.java	(revision 0)
@@ -0,0 +1,65 @@
+/**
+ * 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.solr.core;
+
+import java.io.IOException;
+
+import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.store.Directory;
+import org.apache.solr.SolrTestCaseJ4;
+import org.apache.solr.util.plugin.SolrCoreAware;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class SolrIndexReaderFactoryTest extends SolrTestCaseJ4 {
+  @BeforeClass
+  public static void beforeClass() throws Exception {
+    initCore("solrconfig-solrirf.xml", "schema.xml");
+  }
+
+  /**
+   * Simple test to ensure that alternate IndexReaderFactory is being used.
+   * 
+   * @throws Exception
+   */
+  @Test
+  public void testSolrIRF() throws Exception {
+    assertQ(req("q","*:*","qt","standard"));
+    assertTrue(TestIndexReaderFactory.newReaderCalled);
+    SolrCore core = h.getCore();
+    assertTrue(core == TestIndexReaderFactory.core);
+  }
+
+  static public class TestIndexReaderFactory extends IndexReaderFactory implements SolrCoreAware {
+    static volatile boolean newReaderCalled = false;
+    public static volatile SolrCore core;
+
+    @Override
+    public void inform(SolrCore core) {
+      TestIndexReaderFactory.core = core;
+    }
+    
+    @Override
+    public IndexReader newReader(Directory indexDir, boolean readOnly)
+        throws IOException {
+      TestIndexReaderFactory.newReaderCalled = true;
+      //TestIndexReaderFactory.core = core;
+      return IndexReader.open(indexDir, readOnly);
+    }
+  }
+
+}
Index: solr/core/src/test-files/solr/conf/solrconfig-solrirf.xml
===================================================================
--- solr/core/src/test-files/solr/conf/solrconfig-solrirf.xml	(revision 0)
+++ solr/core/src/test-files/solr/conf/solrconfig-solrirf.xml	(revision 0)
@@ -0,0 +1,24 @@
+<?xml version="1.0" ?>
+
+<!--
+ 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.
+-->
+
+<config>
+  <luceneMatchVersion>${tests.luceneMatchVersion:LUCENE_CURRENT}</luceneMatchVersion>
+  <requestHandler name="standard" class="solr.StandardRequestHandler"></requestHandler>
+  <indexReaderFactory name="IndexReaderFactory" class="org.apache.solr.core.SolrIndexReaderFactoryTest$TestIndexReaderFactory"></indexReaderFactory >
+</config>

Property changes on: solr/core/src/test-files/solr/conf/solrconfig-solrirf.xml
___________________________________________________________________
Added: svn:executable
   + *

Index: solr/core/src/test-files/solr/conf/solrconfig-luceneirf.xml
===================================================================
--- solr/core/src/test-files/solr/conf/solrconfig-luceneirf.xml	(revision 0)
+++ solr/core/src/test-files/solr/conf/solrconfig-luceneirf.xml	(revision 0)
@@ -0,0 +1,25 @@
+<?xml version="1.0" ?>
+
+<!--
+ 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.
+-->
+<config>
+  <luceneMatchVersion>${tests.luceneMatchVersion:LUCENE_CURRENT}</luceneMatchVersion>
+  <requestHandler name="standard" class="solr.StandardRequestHandler"></requestHandler>
+  <indexDefaults>
+    <luceneIndexReaderFactory class="org.apache.solr.core.TestLuceneIndexReaderFactory$TestIndexReaderFactory"/>
+  </indexDefaults>
+</config>
Index: solr/core/src/java/org/apache/solr/update/DirectUpdateHandler2.java
===================================================================
--- solr/core/src/java/org/apache/solr/update/DirectUpdateHandler2.java	(revision 1180777)
+++ solr/core/src/java/org/apache/solr/update/DirectUpdateHandler2.java	(working copy)
@@ -562,4 +562,8 @@
   public String toString() {
     return "DirectUpdateHandler2" + getStatistics();
   }
+  
+  public IndexWriter getWriter() throws IOException {
+    return writer;
+  }
 }
Index: solr/core/src/java/org/apache/solr/update/SolrIndexConfig.java
===================================================================
--- solr/core/src/java/org/apache/solr/update/SolrIndexConfig.java	(revision 1180777)
+++ solr/core/src/java/org/apache/solr/update/SolrIndexConfig.java	(working copy)
@@ -45,7 +45,10 @@
   final String defaultMergePolicyClassName;
   public static final String DEFAULT_MERGE_SCHEDULER_CLASSNAME = ConcurrentMergeScheduler.class.getName();
   static final SolrIndexConfig defaultDefaults = new SolrIndexConfig();
-
+  
+  final String defaultLuceneIndexReaderFactory;
+  public static final String DEFAULT_LUCENE_INDEX_READER_FACTORY = DefaultIndexReaderFactory.class.getName();
+  
   private SolrIndexConfig() {
     luceneVersion = Version.LUCENE_31;
     useCompoundFile = true;
@@ -61,6 +64,8 @@
     mergePolicyInfo = null;
     mergeSchedulerInfo = null;
     defaultMergePolicyClassName = TieredMergePolicy.class.getName();
+    luceneIndexReaderFactoryInfo = null;
+    defaultLuceneIndexReaderFactory = DEFAULT_LUCENE_INDEX_READER_FACTORY;
   }
 
   public final Version luceneVersion;
@@ -79,6 +84,7 @@
   public final PluginInfo mergePolicyInfo;
   public final PluginInfo mergeSchedulerInfo;
   public final int termIndexInterval;
+  public final PluginInfo luceneIndexReaderFactoryInfo;
   
   public String infoStreamFile = null;
 
@@ -91,6 +97,7 @@
     luceneVersion = solrConfig.luceneMatchVersion;
 
     defaultMergePolicyClassName = luceneVersion.onOrAfter(Version.LUCENE_33) ? TieredMergePolicy.class.getName() : LogByteSizeMergePolicy.class.getName();
+    defaultLuceneIndexReaderFactory = DEFAULT_LUCENE_INDEX_READER_FACTORY;
     useCompoundFile=solrConfig.getBool(prefix+"/useCompoundFile", def.useCompoundFile);
     maxBufferedDocs=solrConfig.getInt(prefix+"/maxBufferedDocs",def.maxBufferedDocs);
     maxMergeDocs=solrConfig.getInt(prefix+"/maxMergeDocs",def.maxMergeDocs);
@@ -124,6 +131,8 @@
     } else {
       mergePolicyInfo = getPluginInfo(prefix + "/mergePolicy", solrConfig, def.mergePolicyInfo);
     }
+ 
+    luceneIndexReaderFactoryInfo = getPluginInfo(prefix + "/luceneIndexReaderFactory", solrConfig, def.luceneIndexReaderFactoryInfo);
     
     Object luceneAutoCommit = solrConfig.get(prefix + "/luceneAutoCommit", null);
     if(luceneAutoCommit != null) {
@@ -161,10 +170,15 @@
     iwc.setSimilarity(schema.getSimilarity());
     iwc.setMergePolicy(buildMergePolicy(schema));
     iwc.setMergeScheduler(buildMergeScheduler(schema));
-
+    iwc.setIndexReaderFactory(buildIndexReaderFactory(schema));
     return iwc;
   }
 
+  private org.apache.lucene.index.IndexReaderFactory buildIndexReaderFactory(IndexSchema schema) {
+    String irfClassName = luceneIndexReaderFactoryInfo == null ? DEFAULT_LUCENE_INDEX_READER_FACTORY : luceneIndexReaderFactoryInfo.className;
+    return (org.apache.lucene.index.IndexReaderFactory) schema.getResourceLoader().newInstance(irfClassName);
+  }
+  
   private MergePolicy buildMergePolicy(IndexSchema schema) {
     MergePolicy policy;
     String mpClassName = mergePolicyInfo == null ? defaultMergePolicyClassName : mergePolicyInfo.className;
Index: solr/core/src/java/org/apache/solr/core/SolrResourceLoader.java
===================================================================
--- solr/core/src/java/org/apache/solr/core/SolrResourceLoader.java	(revision 1180777)
+++ solr/core/src/java/org/apache/solr/core/SolrResourceLoader.java	(working copy)
@@ -637,7 +637,9 @@
         SolrRequestHandler.class,
         QueryResponseWriter.class,
         SearchComponent.class,
-        UpdateRequestProcessorFactory.class
+        UpdateRequestProcessorFactory.class,
+        IndexReaderFactory.class,
+        org.apache.lucene.index.IndexReaderFactory.class
       }
     );
 
Index: lucene/src/test/org/apache/lucene/index/TestIndexWriterConfig.java
===================================================================
--- lucene/src/test/org/apache/lucene/index/TestIndexWriterConfig.java	(revision 1180625)
+++ lucene/src/test/org/apache/lucene/index/TestIndexWriterConfig.java	(working copy)
@@ -81,6 +81,7 @@
     assertEquals(IndexWriterConfig.DEFAULT_MAX_THREAD_STATES, conf.getMaxThreadStates());
     assertEquals(IndexWriterConfig.DEFAULT_READER_TERMS_INDEX_DIVISOR, conf.getReaderTermsIndexDivisor());
     assertEquals(TieredMergePolicy.class, conf.getMergePolicy().getClass());
+    assertEquals(DefaultIndexReaderFactory.class, conf.getIndexReaderFactory().getClass());
     
     // Sanity check - validate that all getters are covered.
     Set<String> getters = new HashSet<String>();
@@ -102,6 +103,7 @@
     getters.add("getMaxThreadStates");
     getters.add("getReaderPooling");
     getters.add("getReaderTermsIndexDivisor");
+    getters.add("getIndexReaderFactory");
     for (Method m : IndexWriterConfig.class.getDeclaredMethods()) {
       if (m.getDeclaringClass() == IndexWriterConfig.class && m.getName().startsWith("get")) {
         assertTrue("method " + m.getName() + " is not tested for defaults", getters.contains(m.getName()));
Index: lucene/src/java/org/apache/lucene/index/IndexReaderFactory.java
===================================================================
--- lucene/src/java/org/apache/lucene/index/IndexReaderFactory.java	(revision 0)
+++ lucene/src/java/org/apache/lucene/index/IndexReaderFactory.java	(revision 0)
@@ -0,0 +1,43 @@
+package org.apache.lucene.index;
+
+/**
+ * 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.
+ */
+
+import java.io.IOException;
+import java.util.Collection;
+import java.util.Map;
+
+import org.apache.lucene.index.IndexReader.ReaderFinishedListener;
+import org.apache.lucene.store.Directory;
+
+public abstract class IndexReaderFactory {
+  public abstract DirectoryReader create(IndexWriter writer,
+      SegmentInfos infos, int termInfosIndexDivisor, boolean applyAllDeletes,
+      boolean readOnly) throws IOException;
+  
+  public abstract DirectoryReader create(Directory directory,
+      SegmentInfos infos, SegmentReader[] oldReaders, int[] oldStarts,
+      Map<String,byte[]> oldNormsCache, boolean doClone,
+      int termInfosIndexDivisor,
+      Collection<ReaderFinishedListener> readerFinishedListeners,
+      boolean readOnly) throws IOException;
+  
+  public abstract DirectoryReader create(Directory directory, SegmentInfos sis,
+      IndexDeletionPolicy deletionPolicy, int termInfosIndexDivisor,
+      Collection<ReaderFinishedListener> readerFinishedListeners,
+      boolean readOnly) throws IOException;
+}
Index: lucene/src/java/org/apache/lucene/index/ReadOnlyDirectoryReader.java
===================================================================
--- lucene/src/java/org/apache/lucene/index/ReadOnlyDirectoryReader.java	(revision 1180625)
+++ lucene/src/java/org/apache/lucene/index/ReadOnlyDirectoryReader.java	(working copy)
@@ -23,18 +23,18 @@
 import java.util.Map;
 import java.util.Collection;
 
-class ReadOnlyDirectoryReader extends DirectoryReader {
-  ReadOnlyDirectoryReader(Directory directory, SegmentInfos sis, IndexDeletionPolicy deletionPolicy, int termInfosIndexDivisor,
+public class ReadOnlyDirectoryReader extends DirectoryReader {
+  public ReadOnlyDirectoryReader(Directory directory, SegmentInfos sis, IndexDeletionPolicy deletionPolicy, int termInfosIndexDivisor,
                           Collection<ReaderFinishedListener> readerFinishedListeners) throws IOException {
     super(directory, sis, deletionPolicy, true, termInfosIndexDivisor, readerFinishedListeners);
   }
 
-  ReadOnlyDirectoryReader(Directory directory, SegmentInfos infos, SegmentReader[] oldReaders, int[] oldStarts,  Map<String,byte[]> oldNormsCache, boolean doClone,
+  public ReadOnlyDirectoryReader(Directory directory, SegmentInfos infos, SegmentReader[] oldReaders, int[] oldStarts,  Map<String,byte[]> oldNormsCache, boolean doClone,
                           int termInfosIndexDivisor, Collection<ReaderFinishedListener> readerFinishedListeners) throws IOException {
     super(directory, infos, oldReaders, oldStarts, oldNormsCache, true, doClone, termInfosIndexDivisor, readerFinishedListeners);
   }
   
-  ReadOnlyDirectoryReader(IndexWriter writer, SegmentInfos infos, int termInfosIndexDivisor, boolean applyAllDeletes) throws IOException {
+  public ReadOnlyDirectoryReader(IndexWriter writer, SegmentInfos infos, int termInfosIndexDivisor, boolean applyAllDeletes) throws IOException {
     super(writer, infos, termInfosIndexDivisor, applyAllDeletes);
   }
   
Index: lucene/src/java/org/apache/lucene/index/DirectoryReader.java
===================================================================
--- lucene/src/java/org/apache/lucene/index/DirectoryReader.java	(revision 1180625)
+++ lucene/src/java/org/apache/lucene/index/DirectoryReader.java	(working copy)
@@ -42,7 +42,7 @@
 /** 
  * An IndexReader which reads indexes with multiple segments.
  */
-class DirectoryReader extends IndexReader implements Cloneable {
+public class DirectoryReader extends IndexReader implements Cloneable {
   protected Directory directory;
   protected boolean readOnly;
 
@@ -69,24 +69,29 @@
   private long maxIndexVersion;
 
   private final boolean applyAllDeletes;
+  IndexReaderFactory readerFactory;
 
   static IndexReader open(final Directory directory, final IndexDeletionPolicy deletionPolicy, final IndexCommit commit, final boolean readOnly,
-                          final int termInfosIndexDivisor) throws CorruptIndexException, IOException {
+      final int termInfosIndexDivisor) throws CorruptIndexException, IOException {
+    return open(directory, deletionPolicy, commit, readOnly, termInfosIndexDivisor, new DefaultIndexReaderFactory());
+  }
+  
+  static IndexReader open(final Directory directory, final IndexDeletionPolicy deletionPolicy, final IndexCommit commit, final boolean readOnly,
+                          final int termInfosIndexDivisor, final IndexReaderFactory readerFactory) throws CorruptIndexException, IOException {
     return (IndexReader) new SegmentInfos.FindSegmentsFile(directory) {
       @Override
       protected Object doBody(String segmentFileName) throws CorruptIndexException, IOException {
         SegmentInfos infos = new SegmentInfos();
         infos.read(directory, segmentFileName);
-        if (readOnly)
-          return new ReadOnlyDirectoryReader(directory, infos, deletionPolicy, termInfosIndexDivisor, null);
-        else
-          return new DirectoryReader(directory, infos, deletionPolicy, false, termInfosIndexDivisor, null);
+        DirectoryReader reader = readerFactory.create(directory, infos, deletionPolicy, termInfosIndexDivisor, null, readOnly);
+        reader.readerFactory = readerFactory;
+        return reader;
       }
     }.run(commit);
   }
 
   /** Construct reading the named set of readers. */
-  DirectoryReader(Directory directory, SegmentInfos sis, IndexDeletionPolicy deletionPolicy, boolean readOnly, int termInfosIndexDivisor,
+  public DirectoryReader(Directory directory, SegmentInfos sis, IndexDeletionPolicy deletionPolicy, boolean readOnly, int termInfosIndexDivisor,
                   Collection<ReaderFinishedListener> readerFinishedListeners) throws IOException {
     this.directory = directory;
     this.readOnly = readOnly;
@@ -131,7 +136,7 @@
   }
 
   // Used by near real-time search
-  DirectoryReader(IndexWriter writer, SegmentInfos infos, int termInfosIndexDivisor, boolean applyAllDeletes) throws IOException {
+  public DirectoryReader(IndexWriter writer, SegmentInfos infos, int termInfosIndexDivisor, boolean applyAllDeletes) throws IOException {
     this.directory = writer.getDirectory();
     this.readOnly = true;
     this.applyAllDeletes = applyAllDeletes;       // saved for reopen
@@ -184,7 +189,7 @@
   }
 
   /** This constructor is only used for {@link #doOpenIfChanged()} */
-  DirectoryReader(Directory directory, SegmentInfos infos, SegmentReader[] oldReaders, int[] oldStarts,
+  public DirectoryReader(Directory directory, SegmentInfos infos, SegmentReader[] oldReaders, int[] oldStarts,
                   Map<String,byte[]> oldNormsCache, boolean readOnly, boolean doClone, int termInfosIndexDivisor,
                   Collection<ReaderFinishedListener> readerFinishedListeners) throws IOException {
     this.directory = directory;
@@ -486,12 +491,8 @@
   }
 
   private synchronized DirectoryReader doOpenIfChanged(SegmentInfos infos, boolean doClone, boolean openReadOnly) throws CorruptIndexException, IOException {
-    DirectoryReader reader;
-    if (openReadOnly) {
-      reader = new ReadOnlyDirectoryReader(directory, infos, subReaders, starts, normsCache, doClone, termInfosIndexDivisor, readerFinishedListeners);
-    } else {
-      reader = new DirectoryReader(directory, infos, subReaders, starts, normsCache, false, doClone, termInfosIndexDivisor, readerFinishedListeners);
-    }
+    DirectoryReader reader = readerFactory.create(directory, infos, subReaders, starts, normsCache, doClone, termInfosIndexDivisor, readerFinishedListeners, openReadOnly);
+    reader.readerFactory = readerFactory;
     return reader;
   }
 
Index: lucene/src/java/org/apache/lucene/index/DefaultIndexReaderFactory.java
===================================================================
--- lucene/src/java/org/apache/lucene/index/DefaultIndexReaderFactory.java	(revision 0)
+++ lucene/src/java/org/apache/lucene/index/DefaultIndexReaderFactory.java	(revision 0)
@@ -0,0 +1,72 @@
+package org.apache.lucene.index;
+
+/**
+ * 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.
+ */
+
+import java.io.IOException;
+import java.util.Collection;
+import java.util.Map;
+
+import org.apache.lucene.index.IndexReader.ReaderFinishedListener;
+import org.apache.lucene.store.Directory;
+
+public class DefaultIndexReaderFactory extends IndexReaderFactory {
+  @Override
+  public DirectoryReader create(IndexWriter writer, SegmentInfos infos,
+      int termInfosIndexDivisor, boolean applyAllDeletes, boolean readOnly)
+      throws IOException {
+    if (readOnly) {
+      return new ReadOnlyDirectoryReader(writer, infos, termInfosIndexDivisor,
+          applyAllDeletes);
+    } else {
+      return new DirectoryReader(writer, infos, termInfosIndexDivisor,
+          applyAllDeletes);
+    }
+  }
+  
+  @Override
+  public DirectoryReader create(Directory directory, SegmentInfos infos,
+      SegmentReader[] oldReaders, int[] oldStarts,
+      Map<String,byte[]> oldNormsCache, boolean doClone,
+      int termInfosIndexDivisor,
+      Collection<ReaderFinishedListener> readerFinishedListeners,
+      boolean readOnly) throws IOException {
+    if (readOnly) {
+      return new ReadOnlyDirectoryReader(directory, infos, oldReaders,
+          oldStarts, oldNormsCache, doClone, termInfosIndexDivisor,
+          readerFinishedListeners);
+    } else {
+      return new DirectoryReader(directory, infos, oldReaders, oldStarts,
+          oldNormsCache, readOnly, doClone, termInfosIndexDivisor,
+          readerFinishedListeners);
+    }
+  }
+  
+  @Override
+  public DirectoryReader create(Directory directory, SegmentInfos sis,
+      IndexDeletionPolicy deletionPolicy, int termInfosIndexDivisor,
+      Collection<ReaderFinishedListener> readerFinishedListeners,
+      boolean readOnly) throws IOException {
+    if (readOnly) {
+      return new ReadOnlyDirectoryReader(directory, sis, deletionPolicy,
+          termInfosIndexDivisor, readerFinishedListeners);
+    } else {
+      return new DirectoryReader(directory, sis, deletionPolicy, readOnly,
+          termInfosIndexDivisor, readerFinishedListeners);
+    }
+  }
+}
Index: lucene/src/java/org/apache/lucene/index/IndexReader.java
===================================================================
--- lucene/src/java/org/apache/lucene/index/IndexReader.java	(revision 1180625)
+++ lucene/src/java/org/apache/lucene/index/IndexReader.java	(working copy)
@@ -456,11 +456,19 @@
   public static IndexReader open(final IndexCommit commit, IndexDeletionPolicy deletionPolicy, boolean readOnly, int termInfosIndexDivisor) throws CorruptIndexException, IOException {
     return open(commit.getDirectory(), deletionPolicy, commit, readOnly, termInfosIndexDivisor);
   }
+  
+  public static IndexReader open(final IndexCommit commit, IndexDeletionPolicy deletionPolicy, boolean readOnly, int termInfosIndexDivisor, IndexReaderFactory readerFactory) throws CorruptIndexException, IOException {
+    return open(commit.getDirectory(), deletionPolicy, commit, readOnly, termInfosIndexDivisor, readerFactory);
+  }
 
   private static IndexReader open(final Directory directory, final IndexDeletionPolicy deletionPolicy, final IndexCommit commit, final boolean readOnly, int termInfosIndexDivisor) throws CorruptIndexException, IOException {
     return DirectoryReader.open(directory, deletionPolicy, commit, readOnly, termInfosIndexDivisor);
   }
 
+  private static IndexReader open(final Directory directory, final IndexDeletionPolicy deletionPolicy, final IndexCommit commit, final boolean readOnly, int termInfosIndexDivisor, IndexReaderFactory readerFactory) throws CorruptIndexException, IOException {
+    return DirectoryReader.open(directory, deletionPolicy, commit, readOnly, termInfosIndexDivisor);
+  }
+  
   /**
    * If the index has changed since the provided reader was
    * opened, open and return a new reader; else, return
Index: lucene/src/java/org/apache/lucene/index/IndexWriter.java
===================================================================
--- lucene/src/java/org/apache/lucene/index/IndexWriter.java	(revision 1180625)
+++ lucene/src/java/org/apache/lucene/index/IndexWriter.java	(working copy)
@@ -452,10 +452,12 @@
     // Prevent segmentInfos from changing while opening the
     // reader; in theory we could do similar retry logic,
     // just like we do when loading segments_N
-    IndexReader r;
+    DirectoryReader r;
     synchronized(this) {
       flush(false, applyAllDeletes);
-      r = new ReadOnlyDirectoryReader(this, segmentInfos, termInfosIndexDivisor, applyAllDeletes);
+      IndexReaderFactory readerFactory = config.getIndexReaderFactory();
+      r = readerFactory.create(this, segmentInfos, termInfosIndexDivisor, applyAllDeletes, true);
+      r.readerFactory = readerFactory;
       if (infoStream != null) {
         message("return reader version=" + r.getVersion() + " reader=" + r);
       }
Index: lucene/src/java/org/apache/lucene/index/IndexWriterConfig.java
===================================================================
--- lucene/src/java/org/apache/lucene/index/IndexWriterConfig.java	(revision 1180625)
+++ lucene/src/java/org/apache/lucene/index/IndexWriterConfig.java	(working copy)
@@ -127,6 +127,7 @@
   private volatile int maxThreadStates;
   private volatile boolean readerPooling;
   private volatile int readerTermsIndexDivisor;
+  private volatile IndexReaderFactory readerFactory;
   
   private Version matchVersion;
 
@@ -165,6 +166,7 @@
     maxThreadStates = DEFAULT_MAX_THREAD_STATES;
     readerPooling = DEFAULT_READER_POOLING;
     readerTermsIndexDivisor = DEFAULT_READER_TERMS_INDEX_DIVISOR;
+    readerFactory = new DefaultIndexReaderFactory();
   }
   
   @Override
@@ -442,6 +444,15 @@
     return ramBufferSizeMB;
   }
 
+  public IndexWriterConfig setIndexReaderFactory(IndexReaderFactory readerFactory) {
+    this.readerFactory = readerFactory;
+    return this;
+  }
+  
+  public IndexReaderFactory getIndexReaderFactory() {
+    return readerFactory;
+  }
+  
   /**
    * Determines the minimal number of documents required before the buffered
    * in-memory documents are flushed as a new Segment. Large values generally
@@ -619,6 +630,7 @@
     sb.append("maxThreadStates=").append(maxThreadStates).append("\n");
     sb.append("readerPooling=").append(readerPooling).append("\n");
     sb.append("readerTermsIndexDivisor=").append(readerTermsIndexDivisor).append("\n");
+    sb.append("readerFactory=").append(readerFactory == null ? "null" : readerFactory.getClass().getName()).append("\n");
     return sb.toString();
   }
 }
