You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by sh...@apache.org on 2010/05/31 16:37:12 UTC

svn commit: r949756 - in /lucene/dev/trunk: ./ lucene/ lucene/contrib/ lucene/contrib/highlighter/src/test/ lucene/contrib/instantiated/src/test/org/apache/lucene/store/instantiated/ lucene/src/java/org/apache/lucene/analysis/ lucene/src/java/org/apach...

Author: shaie
Date: Mon May 31 14:37:11 2010
New Revision: 949756

URL: http://svn.apache.org/viewvc?rev=949756&view=rev
Log:
LUCENE-2481: Enhance SnapshotDeletionPolicy to allow taking multiple snapshots (merge from 3x)

Added:
    lucene/dev/trunk/lucene/src/java/org/apache/lucene/index/PersistentSnapshotDeletionPolicy.java
      - copied unchanged from r949730, lucene/dev/branches/branch_3x/lucene/src/java/org/apache/lucene/index/PersistentSnapshotDeletionPolicy.java
    lucene/dev/trunk/lucene/src/test/org/apache/lucene/index/TestPersistentSnapshotDeletionPolicy.java
      - copied unchanged from r949730, lucene/dev/branches/branch_3x/lucene/src/test/org/apache/lucene/index/TestPersistentSnapshotDeletionPolicy.java
Modified:
    lucene/dev/trunk/   (props changed)
    lucene/dev/trunk/lucene/   (props changed)
    lucene/dev/trunk/lucene/CHANGES.txt
    lucene/dev/trunk/lucene/build.xml   (props changed)
    lucene/dev/trunk/lucene/contrib/   (props changed)
    lucene/dev/trunk/lucene/contrib/CHANGES.txt   (props changed)
    lucene/dev/trunk/lucene/contrib/highlighter/src/test/   (props changed)
    lucene/dev/trunk/lucene/contrib/instantiated/src/test/org/apache/lucene/store/instantiated/TestIndicesEquals.java   (props changed)
    lucene/dev/trunk/lucene/src/java/org/apache/lucene/analysis/Tokenizer.java   (props changed)
    lucene/dev/trunk/lucene/src/java/org/apache/lucene/index/SnapshotDeletionPolicy.java
    lucene/dev/trunk/lucene/src/java/org/apache/lucene/search/MultiTermQueryWrapperFilter.java   (props changed)
    lucene/dev/trunk/lucene/src/test/org/apache/lucene/document/TestDateTools.java   (props changed)
    lucene/dev/trunk/lucene/src/test/org/apache/lucene/document/TestNumberTools.java   (props changed)
    lucene/dev/trunk/lucene/src/test/org/apache/lucene/index/TestBackwardsCompatibility.java   (props changed)
    lucene/dev/trunk/lucene/src/test/org/apache/lucene/index/TestIndexWriter.java
    lucene/dev/trunk/lucene/src/test/org/apache/lucene/index/TestSnapshotDeletionPolicy.java
    lucene/dev/trunk/lucene/src/test/org/apache/lucene/util/TestAttributeSource.java   (props changed)
    lucene/dev/trunk/solr/   (props changed)
    lucene/dev/trunk/solr/lib/commons-httpclient-3.1.jar   (props changed)
    lucene/dev/trunk/solr/lib/jcl-over-slf4j-1.5.5.jar   (props changed)
    lucene/dev/trunk/solr/src/common/org/apache/solr/common/   (props changed)
    lucene/dev/trunk/solr/src/maven/solr-core-pom.xml.template   (props changed)
    lucene/dev/trunk/solr/src/maven/solr-solrj-pom.xml.template   (props changed)
    lucene/dev/trunk/solr/src/solrj/org/   (props changed)
    lucene/dev/trunk/solr/src/test/org/apache/solr/client/   (props changed)
    lucene/dev/trunk/solr/src/webapp/src/org/apache/solr/client/solrj/embedded/   (props changed)

Propchange: lucene/dev/trunk/
------------------------------------------------------------------------------
    svn:mergeinfo = /lucene/dev/branches/branch_3x:949730

Propchange: lucene/dev/trunk/lucene/
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Mon May 31 14:37:11 2010
@@ -1,4 +1,4 @@
-/lucene/dev/branches/branch_3x/lucene:943137
+/lucene/dev/branches/branch_3x/lucene:943137,949730
 /lucene/java/branches/flex_1458:824912-931101
 /lucene/java/branches/lucene_2_4:748824
 /lucene/java/branches/lucene_2_9:817269-818600,829134,829881,831036,896850,909334,948516

Modified: lucene/dev/trunk/lucene/CHANGES.txt
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/CHANGES.txt?rev=949756&r1=949755&r2=949756&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/CHANGES.txt (original)
+++ lucene/dev/trunk/lucene/CHANGES.txt Mon May 31 14:37:11 2010
@@ -355,6 +355,11 @@ API Changes
   custom file names. You should use this method to name all your files.
   (Shai Erera) 
   
+* LUCENE-2481: SnapshotDeletionPolicy.snapshot() and release() were replaced
+  with equivalent ones that take a String (id) as argument. You can pass
+  whatever ID you want, as long as you use the same one when calling both. 
+  (Shai Erera)
+  
 Bug fixes
 
 * LUCENE-2119: Don't throw NegativeArraySizeException if you pass

Propchange: lucene/dev/trunk/lucene/build.xml
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Mon May 31 14:37:11 2010
@@ -1,4 +1,4 @@
-/lucene/dev/branches/branch_3x/lucene/build.xml:943137
+/lucene/dev/branches/branch_3x/lucene/build.xml:943137,949730
 /lucene/java/branches/flex_1458/build.xml:824912-931101
 /lucene/java/branches/lucene_2_9/build.xml:909334,948516
 /lucene/java/trunk/build.xml:924483-924731,924781,925176-925462

Propchange: lucene/dev/trunk/lucene/contrib/
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Mon May 31 14:37:11 2010
@@ -1,4 +1,4 @@
-/lucene/dev/branches/branch_3x/lucene/contrib:943137
+/lucene/dev/branches/branch_3x/lucene/contrib:943137,949730
 /lucene/java/branches/flex_1458/contrib:824912-931101
 /lucene/java/branches/lucene_2_4/contrib:748824
 /lucene/java/branches/lucene_2_9/contrib:817269-818600,825998,829134,829816,829881,831036,896850,909334,948516

Propchange: lucene/dev/trunk/lucene/contrib/CHANGES.txt
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Mon May 31 14:37:11 2010
@@ -1,4 +1,4 @@
-/lucene/dev/branches/branch_3x/lucene/contrib/CHANGES.txt:943137
+/lucene/dev/branches/branch_3x/lucene/contrib/CHANGES.txt:943137,949730
 /lucene/java/branches/flex_1458/contrib/CHANGES.txt:824912-931101
 /lucene/java/branches/lucene_2_4/contrib/CHANGES.txt:748824
 /lucene/java/branches/lucene_2_9/contrib/CHANGES.txt:817269-818600,825998,826775,829134,829816,829881,831036,896850,948516

Propchange: lucene/dev/trunk/lucene/contrib/highlighter/src/test/
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Mon May 31 14:37:11 2010
@@ -1,4 +1,4 @@
-/lucene/dev/branches/branch_3x/lucene/contrib/highlighter/src/test:943137
+/lucene/dev/branches/branch_3x/lucene/contrib/highlighter/src/test:943137,949730
 /lucene/java/branches/flex_1458/contrib/highlighter/src/test:824912-931101
 /lucene/java/branches/lucene_2_4/contrib/highlighter/src/test:748824
 /lucene/java/branches/lucene_2_9/contrib/highlighter/src/test:817269-818600,825998,826775,829134,829816,829881,831036,896850,909334,948516

Propchange: lucene/dev/trunk/lucene/contrib/instantiated/src/test/org/apache/lucene/store/instantiated/TestIndicesEquals.java
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Mon May 31 14:37:11 2010
@@ -1,4 +1,4 @@
-/lucene/dev/branches/branch_3x/lucene/contrib/instantiated/src/test/org/apache/lucene/store/instantiated/TestIndicesEquals.java:943137
+/lucene/dev/branches/branch_3x/lucene/contrib/instantiated/src/test/org/apache/lucene/store/instantiated/TestIndicesEquals.java:943137,949730
 /lucene/java/branches/flex_1458/contrib/instantiated/src/test/org/apache/lucene/store/instantiated/TestIndicesEquals.java:824912-931101
 /lucene/java/branches/lucene_2_9/contrib/instantiated/src/test/org/apache/lucene/store/instantiated/TestIndicesEquals.java:909334,948516
 /lucene/java/trunk/contrib/instantiated/src/test/org/apache/lucene/store/instantiated/TestIndicesEquals.java:924483-924731,924781,925176-925462

Propchange: lucene/dev/trunk/lucene/src/java/org/apache/lucene/analysis/Tokenizer.java
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Mon May 31 14:37:11 2010
@@ -1,4 +1,4 @@
-/lucene/dev/branches/branch_3x/lucene/src/java/org/apache/lucene/analysis/Tokenizer.java:943137
+/lucene/dev/branches/branch_3x/lucene/src/java/org/apache/lucene/analysis/Tokenizer.java:943137,949730
 /lucene/java/branches/flex_1458/src/java/org/apache/lucene/analysis/Tokenizer.java:824912-931101
 /lucene/java/branches/lucene_2_9/src/java/org/apache/lucene/analysis/Tokenizer.java:909334,948516
 /lucene/java/trunk/src/java/org/apache/lucene/analysis/Tokenizer.java:924483-924731,924781,925176-925462

Modified: lucene/dev/trunk/lucene/src/java/org/apache/lucene/index/SnapshotDeletionPolicy.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/src/java/org/apache/lucene/index/SnapshotDeletionPolicy.java?rev=949756&r1=949755&r2=949756&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/src/java/org/apache/lucene/index/SnapshotDeletionPolicy.java (original)
+++ lucene/dev/trunk/lucene/src/java/org/apache/lucene/index/SnapshotDeletionPolicy.java Mon May 31 14:37:11 2010
@@ -18,131 +18,345 @@ package org.apache.lucene.index;
  */
 
 import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.ArrayList;
 import java.util.Map;
+import java.util.Set;
+import java.util.Map.Entry;
 import java.io.IOException;
-import org.apache.lucene.store.Directory;
 
-/** A {@link IndexDeletionPolicy} that wraps around any other
- *  {@link IndexDeletionPolicy} and adds the ability to hold and
- *  later release a single "snapshot" of an index.  While
- *  the snapshot is held, the {@link IndexWriter} will not
- *  remove any files associated with it even if the index is
- *  otherwise being actively, arbitrarily changed.  Because
- *  we wrap another arbitrary {@link IndexDeletionPolicy}, this
- *  gives you the freedom to continue using whatever {@link
- *  IndexDeletionPolicy} you would normally want to use with your
- *  index.  Note that you can re-use a single instance of
- *  SnapshotDeletionPolicy across multiple writers as long
- *  as they are against the same index Directory.  Any
- *  snapshot held when a writer is closed will "survive"
- *  when the next writer is opened.
- *
- * @lucene.experimental */
+import org.apache.lucene.store.Directory;
 
+/**
+ * An {@link IndexDeletionPolicy} that wraps around any other
+ * {@link IndexDeletionPolicy} and adds the ability to hold and later release
+ * snapshots of an index. While a snapshot is held, the {@link IndexWriter} will
+ * not remove any files associated with it even if the index is otherwise being
+ * actively, arbitrarily changed. Because we wrap another arbitrary
+ * {@link IndexDeletionPolicy}, this gives you the freedom to continue using
+ * whatever {@link IndexDeletionPolicy} you would normally want to use with your
+ * index.
+ * 
+ * <p>
+ * This class maintains all snapshots in-memory, and so the information is not
+ * persisted and not protected against system failures. If persistency is
+ * important, you can use {@link PersistentSnapshotDeletionPolicy} (or your own
+ * extension) and when creating a new instance of this deletion policy, pass the
+ * persistent snapshots information to
+ * {@link #SnapshotDeletionPolicy(IndexDeletionPolicy, Map)}.
+ * 
+ * @lucene.experimental
+ */
 public class SnapshotDeletionPolicy implements IndexDeletionPolicy {
 
-  private IndexCommit lastCommit;
-  private IndexDeletionPolicy primary;
-  private String snapshot;
-
-  public SnapshotDeletionPolicy(IndexDeletionPolicy primary) {
-    this.primary = primary;
-  }
-
-  public synchronized void onInit(List<? extends IndexCommit> commits) throws IOException {
-    primary.onInit(wrapCommits(commits));
-    lastCommit = commits.get(commits.size()-1);
-  }
-
-  public synchronized void onCommit(List<? extends IndexCommit> commits) throws IOException {
-    primary.onCommit(wrapCommits(commits));
-    lastCommit = commits.get(commits.size()-1);
-  }
-
-  /** Take a snapshot of the most recent commit to the
-   *  index.  You must call release() to free this snapshot.
-   *  Note that while the snapshot is held, the files it
-   *  references will not be deleted, which will consume
-   *  additional disk space in your index. If you take a
-   *  snapshot at a particularly bad time (say just before
-   *  you call optimize()) then in the worst case this could
-   *  consume an extra 1X of your total index size, until
-   *  you release the snapshot. */
-  public synchronized IndexCommit snapshot() {
-    if (lastCommit == null) {
-      throw new IllegalStateException("no index commits to snapshot !");
+  /** Holds a Snapshot's information. */
+  private static class SnapshotInfo {
+    String id;
+    String segmentsFileName;
+    IndexCommit commit;
+    
+    public SnapshotInfo(String id, String segmentsFileName, IndexCommit commit) {
+      this.id = id;
+      this.segmentsFileName = segmentsFileName;
+      this.commit = commit;
     }
     
-    if (snapshot == null)
-      snapshot = lastCommit.getSegmentsFileName();
-    else
-      throw new IllegalStateException("snapshot is already set; please call release() first");
-    return lastCommit;
-  }
-
-  /** Release the currently held snapshot. */
-  public synchronized void release() {
-    if (snapshot != null)
-      snapshot = null;
-    else
-      throw new IllegalStateException("snapshot was not set; please call snapshot() first");
+    @Override
+    public String toString() {
+      return id + " : " + segmentsFileName;
+    }
   }
+  
+  protected class SnapshotCommitPoint extends IndexCommit {
+    protected IndexCommit cp;
 
-  private class MyCommitPoint extends IndexCommit {
-    IndexCommit cp;
-    MyCommitPoint(IndexCommit cp) {
+    protected SnapshotCommitPoint(IndexCommit cp) {
       this.cp = cp;
     }
-    @Override
-    public String getSegmentsFileName() {
-      return cp.getSegmentsFileName();
-    }
-    @Override
-    public Collection<String> getFileNames() throws IOException {
-      return cp.getFileNames();
-    }
-    @Override
-    public Directory getDirectory() {
-      return cp.getDirectory();
+
+    /**
+     * Returns true if this segment can be deleted. The default implementation
+     * returns false if this segment is currently held as snapshot.
+     */
+    protected boolean shouldDelete(String segmentsFileName) {
+      return !segmentsFileToIDs.containsKey(segmentsFileName);
     }
+
     @Override
     public void delete() {
-      synchronized(SnapshotDeletionPolicy.this) {
+      synchronized (SnapshotDeletionPolicy.this) {
         // Suppress the delete request if this commit point is
-        // our current snapshot.
-        if (snapshot == null || !snapshot.equals(getSegmentsFileName()))
+        // currently snapshotted.
+        if (shouldDelete(getSegmentsFileName())) {
           cp.delete();
+        }
       }
     }
+
     @Override
-    public boolean isDeleted() {
-      return cp.isDeleted();
+    public Directory getDirectory() {
+      return cp.getDirectory();
     }
+
     @Override
-    public long getVersion() {
-      return cp.getVersion();
+    public Collection<String> getFileNames() throws IOException {
+      return cp.getFileNames();
     }
+
     @Override
     public long getGeneration() {
       return cp.getGeneration();
     }
+
+    @Override
+    public String getSegmentsFileName() {
+      return cp.getSegmentsFileName();
+    }
+
     @Override
-    public Map<String,String> getUserData() throws IOException {
+    public Map<String, String> getUserData() throws IOException {
       return cp.getUserData();
     }
+
+    @Override
+    public long getVersion() {
+      return cp.getVersion();
+    }
+
+    @Override
+    public boolean isDeleted() {
+      return cp.isDeleted();
+    }
+
     @Override
     public boolean isOptimized() {
       return cp.isOptimized();
     }
   }
 
-  private List<IndexCommit> wrapCommits(List<? extends IndexCommit> commits) {
-    final int count = commits.size();
-    List<IndexCommit> myCommits = new ArrayList<IndexCommit>(count);
-    for(int i=0;i<count;i++)
-      myCommits.add(new MyCommitPoint(commits.get(i)));
-    return myCommits;
+  /** Snapshots info */
+  private Map<String, SnapshotInfo> idToSnapshot = new HashMap<String, SnapshotInfo>();
+
+  // multiple IDs could point to the same commit point (segments file name)
+  private Map<String, Set<String>> segmentsFileToIDs = new HashMap<String, Set<String>>();
+
+  private IndexDeletionPolicy primary;
+  protected IndexCommit lastCommit;
+
+  public SnapshotDeletionPolicy(IndexDeletionPolicy primary) {
+    this.primary = primary;
+  }
+
+  /**
+   * {@link SnapshotDeletionPolicy} wraps another {@link IndexDeletionPolicy} to
+   * enable flexible snapshotting.
+   * 
+   * @param primary
+   *          the {@link IndexDeletionPolicy} that is used on non-snapshotted
+   *          commits. Snapshotted commits, are not deleted until explicitly
+   *          released via {@link #release(String)}
+   * @param snapshotsInfo
+   *          A mapping of snapshot ID to the segments filename that is being
+   *          snapshotted. The expected input would be the output of
+   *          {@link #getSnapshots()}. A null value signals that there are no
+   *          initial snapshots to maintain.
+   */
+  public SnapshotDeletionPolicy(IndexDeletionPolicy primary,
+      Map<String, String> snapshotsInfo) {
+    this(primary);
+
+    if (snapshotsInfo != null) {
+      // Add the ID->segmentIDs here - the actual IndexCommits will be
+      // reconciled on the call to onInit()
+      for (Entry<String, String> e : snapshotsInfo.entrySet()) {
+        registerSnapshotInfo(e.getKey(), e.getValue(), null);
+      }
+    }
+  }
+
+  /**
+   * Checks if the given id is already used by another snapshot, and throws
+   * {@link IllegalStateException} if it is.
+   */
+  protected void checkSnapshotted(String id) {
+    if (isSnapshotted(id)) {
+      throw new IllegalStateException("Snapshot ID " + id
+          + " is already used - must be unique");
+    }
+  }
+
+  /** Registers the given snapshot information. */
+  protected void registerSnapshotInfo(String id, String segment, IndexCommit commit) {
+    idToSnapshot.put(id, new SnapshotInfo(id, segment, commit));
+    Set<String> ids = segmentsFileToIDs.get(segment);
+    if (ids == null) {
+      ids = new HashSet<String>();
+      segmentsFileToIDs.put(segment, ids);
+    }
+    ids.add(id);
+  }
+
+  protected List<IndexCommit> wrapCommits(List<? extends IndexCommit> commits) {
+    List<IndexCommit> wrappedCommits = new ArrayList<IndexCommit>(commits.size());
+    for (IndexCommit ic : commits) {
+      wrappedCommits.add(new SnapshotCommitPoint(ic));
+    }
+    return wrappedCommits;
+  }
+
+  /**
+   * Get a snapshotted IndexCommit by ID. The IndexCommit can then be used to
+   * open an IndexReader on a specific commit point, or rollback the index by
+   * opening an IndexWriter with the IndexCommit specified in its
+   * {@link IndexWriterConfig}.
+   * 
+   * @param id
+   *          a unique identifier of the commit that was snapshotted.
+   * @throws IllegalStateException
+   *           if no snapshot exists by the specified ID.
+   * @return The {@link IndexCommit} for this particular snapshot.
+   */
+  public synchronized IndexCommit getSnapshot(String id) {
+    SnapshotInfo snapshotInfo = idToSnapshot.get(id);
+    if (snapshotInfo == null) {
+      throw new IllegalStateException("No snapshot exists by ID: " + id);
+    }
+    return snapshotInfo.commit;
+  }
+
+  /**
+   * Get all the snapshots in a map of snapshot IDs to the segments they
+   * 'cover.' This can be passed to
+   * {@link #SnapshotDeletionPolicy(IndexDeletionPolicy, Map)} in order to
+   * initialize snapshots at construction.
+   */
+  public synchronized Map<String, String> getSnapshots() {
+    Map<String, String> snapshots = new HashMap<String, String>();
+    for (Entry<String, SnapshotInfo> e : idToSnapshot.entrySet()) {
+      snapshots.put(e.getKey(), e.getValue().segmentsFileName);
+    }
+    return snapshots;
+  }
+
+  /**
+   * Returns true if the given ID is already used by a snapshot. You can call
+   * this method before {@link #snapshot(String)} if you are not sure whether
+   * the ID is already used or not.
+   */
+  public boolean isSnapshotted(String id) {
+    return idToSnapshot.containsKey(id);
+  }
+
+  public synchronized void onCommit(List<? extends IndexCommit> commits)
+      throws IOException {
+    primary.onCommit(wrapCommits(commits));
+    lastCommit = commits.get(commits.size() - 1);
   }
+
+  public synchronized void onInit(List<? extends IndexCommit> commits)
+      throws IOException {
+    primary.onInit(wrapCommits(commits));
+    lastCommit = commits.get(commits.size() - 1);
+
+    /*
+     * Assign snapshotted IndexCommits to their correct snapshot IDs as
+     * specified in the constructor.
+     */
+    for (IndexCommit commit : commits) {
+      Set<String> ids = segmentsFileToIDs.get(commit.getSegmentsFileName());
+      if (ids != null) {
+        for (String id : ids) {
+          idToSnapshot.get(id).commit = commit;
+        }
+      }
+    }
+
+    /*
+     * Second, see if there are any instances where a snapshot ID was specified
+     * in the constructor but an IndexCommit doesn't exist. In this case, the ID
+     * should be removed.
+     * 
+     * Note: This code is protective for extreme cases where IDs point to
+     * non-existent segments. As the constructor should have received its
+     * information via a call to getSnapshots(), the data should be well-formed.
+     */
+    // Find lost snapshots
+    ArrayList<String> idsToRemove = null;
+    for (Entry<String, SnapshotInfo> e : idToSnapshot.entrySet()) {
+      if (e.getValue().commit == null) {
+        if (idsToRemove == null) {
+          idsToRemove = new ArrayList<String>();
+        }
+        idsToRemove.add(e.getKey());
+      }
+    }
+    // Finally, remove those 'lost' snapshots.
+    if (idsToRemove != null) {
+      for (String id : idsToRemove) {
+        SnapshotInfo info = idToSnapshot.remove(id);
+        segmentsFileToIDs.remove(info.segmentsFileName);
+      }
+    }
+  }
+
+  /**
+   * Release a snapshotted commit by ID.
+   * 
+   * @param id
+   *          a unique identifier of the commit that is un-snapshotted.
+   * @throws IllegalStateException
+   *           if no snapshot exists by this ID.
+   */
+  public synchronized void release(String id) throws IOException {
+    SnapshotInfo info = idToSnapshot.remove(id);
+    if (info == null) {
+      throw new IllegalStateException("Snapshot doesn't exist: " + id);
+    }
+    Set<String> ids = segmentsFileToIDs.get(info.segmentsFileName);
+    if (ids != null) {
+      ids.remove(id);
+      if (ids.size() == 0) {
+        segmentsFileToIDs.remove(info.segmentsFileName);
+      }
+    }
+  }
+
+  /**
+   * Snapshots the last commit. Once a commit is 'snapshotted,' it is protected
+   * from deletion (as long as this {@link IndexDeletionPolicy} is used). The
+   * commit can be removed by calling {@link #release(String)} using the same ID
+   * parameter followed by a call to {@link IndexWriter#deleteUnusedFiles()}.
+   * <p>
+   * <b>NOTE:</b> ID must be unique in the system. If the same ID is used twice,
+   * an {@link IllegalStateException} is thrown.
+   * <p>
+   * <b>NOTE:</b> while the snapshot is held, the files it references will not
+   * be deleted, which will consume additional disk space in your index. If you
+   * take a snapshot at a particularly bad time (say just before you call
+   * optimize()) then in the worst case this could consume an extra 1X of your
+   * total index size, until you release the snapshot.
+   * 
+   * @param id
+   *          a unique identifier of the commit that is being snapshotted.
+   * @throws IllegalStateException
+   *           if either there is no 'last commit' to snapshot, or if the
+   *           parameter 'ID' refers to an already snapshotted commit.
+   * @return the {@link IndexCommit} that was snapshotted.
+   */
+  public synchronized IndexCommit snapshot(String id) throws IOException {
+    if (lastCommit == null) {
+      // no commit exists. Really shouldn't happen, but might be if SDP is
+      // accessed before onInit or onCommit were called.
+      throw new IllegalStateException("No index commit to snapshot");
+    }
+
+    // Can't use the same snapshot ID twice...
+    checkSnapshotted(id);
+
+    registerSnapshotInfo(id, lastCommit.getSegmentsFileName(), lastCommit);
+    return lastCommit;
+  }
+
 }

Propchange: lucene/dev/trunk/lucene/src/java/org/apache/lucene/search/MultiTermQueryWrapperFilter.java
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Mon May 31 14:37:11 2010
@@ -1,4 +1,4 @@
-/lucene/dev/branches/branch_3x/lucene/src/java/org/apache/lucene/search/MultiTermQueryWrapperFilter.java:943137
+/lucene/dev/branches/branch_3x/lucene/src/java/org/apache/lucene/search/MultiTermQueryWrapperFilter.java:943137,949730
 /lucene/java/branches/flex_1458/src/java/org/apache/lucene/search/MultiTermQueryWrapperFilter.java:824912-931101
 /lucene/java/branches/lucene_2_9/src/java/org/apache/lucene/search/MultiTermQueryWrapperFilter.java:909334,948516
 /lucene/java/trunk/src/java/org/apache/lucene/search/MultiTermQueryWrapperFilter.java:924483-924731,924781,925176-925462

Propchange: lucene/dev/trunk/lucene/src/test/org/apache/lucene/document/TestDateTools.java
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Mon May 31 14:37:11 2010
@@ -1,4 +1,4 @@
-/lucene/dev/branches/branch_3x/lucene/src/test/org/apache/lucene/document/TestDateTools.java:943137
+/lucene/dev/branches/branch_3x/lucene/src/test/org/apache/lucene/document/TestDateTools.java:943137,949730
 /lucene/java/branches/flex_1458/src/test/org/apache/lucene/document/TestDateTools.java:824912-931101
 /lucene/java/branches/lucene_2_4/src/test/org/apache/lucene/document/TestDateTools.java:748824
 /lucene/java/branches/lucene_2_9/src/test/org/apache/lucene/document/TestDateTools.java:829134,829881,831036,896850,909334,948516

Propchange: lucene/dev/trunk/lucene/src/test/org/apache/lucene/document/TestNumberTools.java
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Mon May 31 14:37:11 2010
@@ -1,4 +1,4 @@
-/lucene/dev/branches/branch_3x/lucene/src/test/org/apache/lucene/document/TestNumberTools.java:943137
+/lucene/dev/branches/branch_3x/lucene/src/test/org/apache/lucene/document/TestNumberTools.java:943137,949730
 /lucene/java/branches/flex_1458/src/test/org/apache/lucene/document/TestNumberTools.java:824912-931101
 /lucene/java/branches/lucene_2_4/src/test/org/apache/lucene/document/TestNumberTools.java:748824
 /lucene/java/branches/lucene_2_9/src/test/org/apache/lucene/document/TestNumberTools.java:829134,829881,831036,896850,909334,948516

Propchange: lucene/dev/trunk/lucene/src/test/org/apache/lucene/index/TestBackwardsCompatibility.java
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Mon May 31 14:37:11 2010
@@ -1,4 +1,4 @@
-/lucene/dev/branches/branch_3x/lucene/src/test/org/apache/lucene/index/TestBackwardsCompatibility.java:943137
+/lucene/dev/branches/branch_3x/lucene/src/test/org/apache/lucene/index/TestBackwardsCompatibility.java:943137,949730
 /lucene/java/branches/flex_1458/src/test/org/apache/lucene/index/TestBackwardsCompatibility.java:824912-931101
 /lucene/java/branches/lucene_2_4/src/test/org/apache/lucene/index/TestBackwardsCompatibility.java:748824
 /lucene/java/branches/lucene_2_9/src/test/org/apache/lucene/index/TestBackwardsCompatibility.java:829134,829881,831036,896850,909334,948516

Modified: lucene/dev/trunk/lucene/src/test/org/apache/lucene/index/TestIndexWriter.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/src/test/org/apache/lucene/index/TestIndexWriter.java?rev=949756&r1=949755&r2=949756&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/src/test/org/apache/lucene/index/TestIndexWriter.java (original)
+++ lucene/dev/trunk/lucene/src/test/org/apache/lucene/index/TestIndexWriter.java Mon May 31 14:37:11 2010
@@ -4838,7 +4838,7 @@ public class TestIndexWriter extends Luc
     assertEquals(1, IndexReader.listCommits(dir).size());
 
     // Keep that commit
-    sdp.snapshot();
+    sdp.snapshot("id");
     
     // Second commit - now KeepOnlyLastCommit cannot delete the prev commit.
     doc = new Document();
@@ -4848,7 +4848,7 @@ public class TestIndexWriter extends Luc
     assertEquals(2, IndexReader.listCommits(dir).size());
 
     // Should delete the unreferenced commit
-    sdp.release();
+    sdp.release("id");
     writer.deleteUnusedFiles();
     assertEquals(1, IndexReader.listCommits(dir).size());
     

Modified: lucene/dev/trunk/lucene/src/test/org/apache/lucene/index/TestSnapshotDeletionPolicy.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/src/test/org/apache/lucene/index/TestSnapshotDeletionPolicy.java?rev=949756&r1=949755&r2=949756&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/src/test/org/apache/lucene/index/TestSnapshotDeletionPolicy.java (original)
+++ lucene/dev/trunk/lucene/src/test/org/apache/lucene/index/TestSnapshotDeletionPolicy.java Mon May 31 14:37:11 2010
@@ -1,25 +1,9 @@
 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 static org.junit.Assert.*;
 
 import java.util.Collection;
+import java.util.Map;
 import java.io.File;
 import java.io.IOException;
 
@@ -46,9 +30,58 @@ import org.junit.Test;
 //
 
 public class TestSnapshotDeletionPolicy extends LuceneTestCaseJ4 {
-  
+	
   public static final String INDEX_PATH = "test.snapshots";
 
+  protected IndexWriterConfig getConfig(IndexDeletionPolicy dp) {
+    IndexWriterConfig conf = new IndexWriterConfig(TEST_VERSION_CURRENT, new MockAnalyzer());
+    if (dp != null) {
+      conf.setIndexDeletionPolicy(dp);
+    }
+    return conf;
+  }
+
+  protected void checkSnapshotExists(Directory dir, IndexCommit c) throws Exception {
+    String segFileName = c.getSegmentsFileName();
+    assertTrue("segments file not found in directory: " + segFileName, dir.fileExists(segFileName));
+  }
+
+  protected void checkMaxDoc(IndexCommit commit, int expectedMaxDoc) throws Exception {
+    IndexReader reader = IndexReader.open(commit, true);
+    try {
+      assertEquals(expectedMaxDoc, reader.maxDoc());
+    } finally {
+      reader.close();
+    }
+  }
+
+  protected void prepareIndexAndSnapshots(SnapshotDeletionPolicy sdp,
+      IndexWriter writer, int numSnapshots, String snapshotPrefix)
+      throws RuntimeException, IOException {
+    for (int i = 0; i < numSnapshots; i++) {
+      // create dummy document to trigger commit.
+      writer.addDocument(new Document());
+      writer.commit();
+      sdp.snapshot(snapshotPrefix + i);
+    }
+  }
+
+  protected SnapshotDeletionPolicy getDeletionPolicy() throws IOException {
+    return getDeletionPolicy(null);
+  }
+
+  protected SnapshotDeletionPolicy getDeletionPolicy(Map<String, String> snapshots) throws IOException {
+    return new SnapshotDeletionPolicy(new KeepOnlyLastCommitDeletionPolicy(), snapshots);
+  }
+
+  protected void assertSnapshotExists(Directory dir, SnapshotDeletionPolicy sdp, int numSnapshots) throws Exception {
+    for (int i = 0; i < numSnapshots; i++) {
+      IndexCommit snapshot = sdp.getSnapshot("snapshot" + i);
+      checkMaxDoc(snapshot, i + 1);
+      checkSnapshotExists(dir, snapshot);
+    }
+  }
+  
   @Test
   public void testSnapshotDeletionPolicy() throws Exception {
     File dir = _TestUtil.getTempDir(INDEX_PATH);
@@ -65,61 +98,13 @@ public class TestSnapshotDeletionPolicy 
     dir2.close();
   }
 
-  @Test
-  public void testReuseAcrossWriters() throws Exception {
-    Directory dir = new MockRAMDirectory();
-
-    SnapshotDeletionPolicy dp = new SnapshotDeletionPolicy(new KeepOnlyLastCommitDeletionPolicy());
-    IndexWriter writer = new IndexWriter(dir, new IndexWriterConfig(
-        TEST_VERSION_CURRENT, 
-        new MockAnalyzer()).setIndexDeletionPolicy(dp)
-        .setMaxBufferedDocs(2));
-    Document doc = new Document();
-    doc.add(new Field("content", "aaa", Field.Store.YES, Field.Index.ANALYZED, Field.TermVector.WITH_POSITIONS_OFFSETS));
-    for(int i=0;i<7;i++) {
-      writer.addDocument(doc);
-      if (i % 2 == 0) {
-        writer.commit();
-      }
-    }
-    IndexCommit cp = dp.snapshot();
-    copyFiles(dir, cp);
-    writer.close();
-    copyFiles(dir, cp);
-    
-    writer = new IndexWriter(dir, new IndexWriterConfig(TEST_VERSION_CURRENT,
-        new MockAnalyzer()).setIndexDeletionPolicy(dp));
-    copyFiles(dir, cp);
-    for(int i=0;i<7;i++) {
-      writer.addDocument(doc);
-      if (i % 2 == 0) {
-        writer.commit();
-      }
-    }
-    copyFiles(dir, cp);
-    writer.close();
-    copyFiles(dir, cp);
-    dp.release();
-    writer = new IndexWriter(dir, new IndexWriterConfig(TEST_VERSION_CURRENT,
-        new MockAnalyzer()).setIndexDeletionPolicy(dp));
-    writer.close();
-    try {
-      copyFiles(dir, cp);
-      fail("did not hit expected IOException");
-    } catch (IOException ioe) {
-      // expected
-    }
-    dir.close();
-  }
-
   private void runTest(Directory dir) throws Exception {
     // Run for ~1 seconds
     final long stopTime = System.currentTimeMillis() + 1000;
 
-    SnapshotDeletionPolicy dp = new SnapshotDeletionPolicy(new KeepOnlyLastCommitDeletionPolicy());
+    SnapshotDeletionPolicy dp = getDeletionPolicy();
     final IndexWriter writer = new IndexWriter(dir, new IndexWriterConfig(
-        TEST_VERSION_CURRENT, 
-        new MockAnalyzer()).setIndexDeletionPolicy(dp)
+        TEST_VERSION_CURRENT, new MockAnalyzer()).setIndexDeletionPolicy(dp)
         .setMaxBufferedDocs(2));
     writer.commit();
     
@@ -177,20 +162,21 @@ public class TestSnapshotDeletionPolicy 
     TestIndexWriter.assertNoUnreferencedFiles(dir, "some files were not deleted but should have been");
   }
 
-  /** Example showing how to use the SnapshotDeletionPolicy
-   *  to take a backup.  This method does not really do a
-   *  backup; instead, it reads every byte of every file
-   *  just to test that the files indeed exist and are
-   *  readable even while the index is changing. */
+  /**
+   * Example showing how to use the SnapshotDeletionPolicy to take a backup.
+   * This method does not really do a backup; instead, it reads every byte of
+   * every file just to test that the files indeed exist and are readable even
+   * while the index is changing.
+   */
   public void backupIndex(Directory dir, SnapshotDeletionPolicy dp) throws Exception {
     // To backup an index we first take a snapshot:
     try {
-      copyFiles(dir,  dp.snapshot());
+      copyFiles(dir,  dp.snapshot("id"));
     } finally {
       // Make sure to release the snapshot, otherwise these
       // files will never be deleted during this IndexWriter
       // session:
-      dp.release();
+      dp.release("id");
     }
   }
 
@@ -237,13 +223,210 @@ public class TestSnapshotDeletionPolicy 
       input.close();
     }
   }
+
   
-  @Test(expected=IllegalStateException.class)
-  public void testNoCommits() throws Exception {
-    // Tests that if there were no commits when snapshot() is called, then
-    // IllegalStateException is thrown rather than NPE.
-    SnapshotDeletionPolicy sdp = new SnapshotDeletionPolicy(new KeepOnlyLastCommitDeletionPolicy());
-    sdp.snapshot();
+  @Test
+  public void testBasicSnapshots() throws Exception {
+    int numSnapshots = 3;
+    SnapshotDeletionPolicy sdp = getDeletionPolicy();
+
+    // Create 3 snapshots: snapshot0, snapshot1, snapshot2
+    Directory dir = new MockRAMDirectory();
+    IndexWriter writer = new IndexWriter(dir, getConfig(sdp));
+    prepareIndexAndSnapshots(sdp, writer, numSnapshots, "snapshot");
+    writer.close();
+    
+    assertSnapshotExists(dir, sdp, numSnapshots);
+
+    // open a reader on a snapshot - should succeed.
+    IndexReader.open(sdp.getSnapshot("snapshot0"), true).close();
+
+    // open a new IndexWriter w/ no snapshots to keep and assert that all snapshots are gone.
+    sdp = getDeletionPolicy();
+    writer = new IndexWriter(dir, getConfig(sdp));
+    writer.deleteUnusedFiles();
+    writer.close();
+    assertEquals("no snapshots should exist", 1, IndexReader.listCommits(dir).size());
+    
+    for (int i = 0; i < numSnapshots; i++) {
+      try {
+        sdp.getSnapshot("snapshot" + i);
+        fail("snapshot shouldn't have existed, but did: snapshot" + i);
+      } catch (IllegalStateException e) {
+        // expected - snapshot should not exist
+      }
+    }
+  }
+
+  @Test
+  public void testMultiThreadedSnapshotting() throws Exception {
+    Directory dir = new MockRAMDirectory();
+    final SnapshotDeletionPolicy sdp = getDeletionPolicy();
+    final IndexWriter writer = new IndexWriter(dir, getConfig(sdp));
+
+    Thread[] threads = new Thread[10];
+    for (int i = 0; i < threads.length; i++) {
+      threads[i] = new Thread() {
+        @Override
+        public void run() {
+          try {
+            writer.addDocument(new Document());
+            writer.commit();
+            sdp.snapshot(getName());
+          } catch (Exception e) {
+            throw new RuntimeException(e);
+          }
+        }
+      };
+      threads[i].setName("t" + i);
+    }
+    
+    for (Thread t : threads) {
+      t.start();
+    }
+    
+    for (Thread t : threads) {
+      t.join();
+    }
+
+    // Do one last commit, so that after we release all snapshots, we stay w/ one commit
+    writer.addDocument(new Document());
+    writer.commit();
+    
+    for (Thread t : threads) {
+      sdp.release(t.getName());
+      writer.deleteUnusedFiles();
+    }
+    assertEquals(1, IndexReader.listCommits(dir).size());
+    writer.close();
+  }
+
+  @Test
+  public void testRollbackToOldSnapshot() throws Exception {
+    int numSnapshots = 2;
+    Directory dir = new MockRAMDirectory();
+    SnapshotDeletionPolicy sdp = getDeletionPolicy();
+    IndexWriter writer = new IndexWriter(dir, getConfig(sdp));
+    prepareIndexAndSnapshots(sdp, writer, numSnapshots, "snapshot");
+    writer.close();
+
+    // now open the writer on "snapshot0" - make sure it succeeds
+    writer = new IndexWriter(dir, getConfig(sdp).setIndexCommit(sdp.getSnapshot("snapshot0")));
+    // this does the actual rollback
+    writer.commit();
+    writer.deleteUnusedFiles();
+    assertSnapshotExists(dir, sdp, numSnapshots - 1);
+    
+    // but 'snapshot1' files will still exist (need to release snapshot before they can be deleted).
+    String segFileName = sdp.getSnapshot("snapshot1").getSegmentsFileName();
+    assertTrue("snapshot files should exist in the directory: " + segFileName, dir.fileExists(segFileName));
+  }
+
+  @Test
+  public void testReleaseSnapshot() throws Exception {
+    Directory dir = new MockRAMDirectory();
+    SnapshotDeletionPolicy sdp = getDeletionPolicy();
+    IndexWriter writer = new IndexWriter(dir, getConfig(sdp));
+    prepareIndexAndSnapshots(sdp, writer, 1, "snapshot");
+    
+    // Create another commit - we must do that, because otherwise the "snapshot"
+    // files will still remain in the index, since it's the last commit.
+    writer.addDocument(new Document());
+    writer.commit();
+    
+    // Release
+    String snapId = "snapshot0";
+    String segFileName = sdp.getSnapshot(snapId).getSegmentsFileName();
+    sdp.release(snapId);
+    try {
+      sdp.getSnapshot(snapId);
+      fail("should not have succeeded to get an unsnapshotted id");
+    } catch (IllegalStateException e) {
+      // expected
+    }
+    assertNull(sdp.getSnapshots().get(snapId));
+    writer.deleteUnusedFiles();
+    assertFalse("segments file should not be found in dirctory: " + segFileName, dir.fileExists(segFileName));
+  }
+
+  @Test
+  public void testExistingSnapshots() throws Exception {
+    // Tests the ability to construct a SDP from existing snapshots, and
+    // asserts that those snapshots/commit points are protected.
+    int numSnapshots = 3;
+    Directory dir = new MockRAMDirectory();
+    SnapshotDeletionPolicy sdp = getDeletionPolicy();
+    IndexWriter writer = new IndexWriter(dir, getConfig(sdp));
+    prepareIndexAndSnapshots(sdp, writer, numSnapshots, "snapshot");
+    writer.close();
+
+    // Make a new policy and initialize with snapshots.
+    sdp = getDeletionPolicy(sdp.getSnapshots());
+    writer = new IndexWriter(dir, getConfig(sdp));
+    // attempt to delete unused files - the snapshotted files should not be deleted
+    writer.deleteUnusedFiles();
+    writer.close();
+    assertSnapshotExists(dir, sdp, numSnapshots);
+  }
+
+  @Test
+  public void testSnapshotLastCommitTwice() throws Exception {
+    Directory dir = new MockRAMDirectory();
+    SnapshotDeletionPolicy sdp = getDeletionPolicy();
+    IndexWriter writer = new IndexWriter(dir, getConfig(sdp));
+    writer.addDocument(new Document());
+    writer.commit();
+    
+    String s1 = "s1";
+    String s2 = "s2";
+    IndexCommit ic1 = sdp.snapshot(s1);
+    IndexCommit ic2 = sdp.snapshot(s2);
+    assertTrue(ic1 == ic2); // should be the same instance
+    
+    // create another commit
+    writer.addDocument(new Document());
+    writer.commit();
+    
+    // release "s1" should not delete "s2"
+    sdp.release(s1);
+    writer.deleteUnusedFiles();
+    checkSnapshotExists(dir, ic2);
+    
+    writer.close();
   }
   
+  @Test
+  public void testMissingCommits() throws Exception {
+    // Tests the behavior of SDP when commits that are given at ctor are missing
+    // on onInit().
+    Directory dir = new MockRAMDirectory();
+    SnapshotDeletionPolicy sdp = getDeletionPolicy();
+    IndexWriter writer = new IndexWriter(dir, getConfig(sdp));
+    writer.addDocument(new Document());
+    writer.commit();
+    IndexCommit ic = sdp.snapshot("s1");
+
+    // create another commit, not snapshotted.
+    writer.addDocument(new Document());
+    writer.close();
+
+    // open a new writer w/ KeepOnlyLastCommit policy, so it will delete "s1"
+    // commit.
+    new IndexWriter(dir, getConfig(null)).close();
+    
+    assertFalse("snapshotted commit should not exist", dir.fileExists(ic.getSegmentsFileName()));
+    
+    // Now reinit SDP from the commits in the index - the snapshot id should not
+    // exist anymore.
+    sdp = getDeletionPolicy(sdp.getSnapshots());
+    new IndexWriter(dir, getConfig(sdp)).close();
+    
+    try {
+      sdp.getSnapshot("s1");
+      fail("snapshot s1 should not exist");
+    } catch (IllegalStateException e) {
+      // expected.
+    }
+  }
+
 }

Propchange: lucene/dev/trunk/lucene/src/test/org/apache/lucene/util/TestAttributeSource.java
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Mon May 31 14:37:11 2010
@@ -1,4 +1,4 @@
-/lucene/dev/branches/branch_3x/lucene/src/test/org/apache/lucene/util/TestAttributeSource.java:943137
+/lucene/dev/branches/branch_3x/lucene/src/test/org/apache/lucene/util/TestAttributeSource.java:943137,949730
 /lucene/java/branches/flex_1458/src/test/org/apache/lucene/util/TestAttributeSource.java:824912-931101
 /lucene/java/branches/lucene_2_9/src/test/org/apache/lucene/util/TestAttributeSource.java:909334,948516
 /lucene/java/trunk/src/test/org/apache/lucene/util/TestAttributeSource.java:924483-924731,924781,925176-925462

Propchange: lucene/dev/trunk/solr/
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Mon May 31 14:37:11 2010
@@ -1,3 +1,4 @@
+/lucene/dev/branches/branch_3x/solr:949730
 /lucene/java/branches/lucene_2_4/solr:748824
 /lucene/java/branches/lucene_2_9/solr:817269-818600,825998,829134,829881,831036,896850,909334
 /lucene/java/branches/lucene_2_9_back_compat_tests/solr:818601-821336

Propchange: lucene/dev/trunk/solr/lib/commons-httpclient-3.1.jar
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Mon May 31 14:37:11 2010
@@ -1 +1,2 @@
+/lucene/dev/branches/branch_3x/solr/lib/commons-httpclient-3.1.jar:949730
 /lucene/solr/trunk/lib/commons-httpclient-3.1.jar:922950-923910,923912-925091

Propchange: lucene/dev/trunk/solr/lib/jcl-over-slf4j-1.5.5.jar
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Mon May 31 14:37:11 2010
@@ -1 +1,2 @@
+/lucene/dev/branches/branch_3x/solr/lib/jcl-over-slf4j-1.5.5.jar:949730
 /lucene/solr/trunk/lib/jcl-over-slf4j-1.5.5.jar:922950-923910,923912-925091

Propchange: lucene/dev/trunk/solr/src/common/org/apache/solr/common/
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Mon May 31 14:37:11 2010
@@ -1 +1,2 @@
+/lucene/dev/branches/branch_3x/solr/src/common/org/apache/solr/common:949730
 /lucene/solr/trunk/src/common/org/apache/solr/common:922950-923910,923912-925091

Propchange: lucene/dev/trunk/solr/src/maven/solr-core-pom.xml.template
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Mon May 31 14:37:11 2010
@@ -1 +1,2 @@
+/lucene/dev/branches/branch_3x/solr/src/maven/solr-core-pom.xml.template:949730
 /lucene/solr/trunk/src/maven/solr-core-pom.xml.template:922950-923910,923912-925091

Propchange: lucene/dev/trunk/solr/src/maven/solr-solrj-pom.xml.template
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Mon May 31 14:37:11 2010
@@ -1 +1,2 @@
+/lucene/dev/branches/branch_3x/solr/src/maven/solr-solrj-pom.xml.template:949730
 /lucene/solr/trunk/src/maven/solr-solrj-pom.xml.template:922950-923910,923912-925091

Propchange: lucene/dev/trunk/solr/src/solrj/org/
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Mon May 31 14:37:11 2010
@@ -1 +1,2 @@
+/lucene/dev/branches/branch_3x/solr/src/solrj/org:949730
 /lucene/solr/trunk/src/solrj/org:922950-923910,923912-925091

Propchange: lucene/dev/trunk/solr/src/test/org/apache/solr/client/
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Mon May 31 14:37:11 2010
@@ -1 +1,2 @@
+/lucene/dev/branches/branch_3x/solr/src/test/org/apache/solr/client:949730
 /lucene/solr/trunk/src/test/org/apache/solr/client:922950-923910,923912-925091

Propchange: lucene/dev/trunk/solr/src/webapp/src/org/apache/solr/client/solrj/embedded/
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Mon May 31 14:37:11 2010
@@ -1 +1,2 @@
+/lucene/dev/branches/branch_3x/solr/src/webapp/src/org/apache/solr/client/solrj/embedded:949730
 /lucene/solr/trunk/src/webapp/src/org/apache/solr/client/solrj/embedded:922950-923910,923912-925091