You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by mi...@apache.org on 2012/06/11 19:47:48 UTC

svn commit: r1348942 - /lucene/dev/branches/branch_4x/lucene/core/src/java/org/apache/lucene/index/SegmentInfos.java

Author: mikemccand
Date: Mon Jun 11 17:47:47 2012
New Revision: 1348942

URL: http://svn.apache.org/viewvc?rev=1348942&view=rev
Log:
LUCENE-4128: be more careful on upgrading a 3.x segments_N file to individual .si files so that OS or JVM crash, or machine power loss, doesn't leave index unusable

Modified:
    lucene/dev/branches/branch_4x/lucene/core/src/java/org/apache/lucene/index/SegmentInfos.java

Modified: lucene/dev/branches/branch_4x/lucene/core/src/java/org/apache/lucene/index/SegmentInfos.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_4x/lucene/core/src/java/org/apache/lucene/index/SegmentInfos.java?rev=1348942&r1=1348941&r2=1348942&view=diff
==============================================================================
--- lucene/dev/branches/branch_4x/lucene/core/src/java/org/apache/lucene/index/SegmentInfos.java (original)
+++ lucene/dev/branches/branch_4x/lucene/core/src/java/org/apache/lucene/index/SegmentInfos.java Mon Jun 11 17:47:47 2012
@@ -337,9 +337,12 @@ public final class SegmentInfos implemen
   // before finishCommit is called
   ChecksumIndexOutput pendingSegnOutput;
 
+  private static final String SEGMENT_INFO_UPGRADE_CODEC = "SegmentInfo3xUpgrade";
+  private static final int SEGMENT_INFO_UPGRADE_VERSION = 0;
+
   private void write(Directory directory) throws IOException {
 
-    String segmentFileName = getNextSegmentFileName();
+    String segmentsFileName = getNextSegmentFileName();
     
     // Always advance the generation on write:
     if (generation == -1) {
@@ -354,7 +357,7 @@ public final class SegmentInfos implemen
     final Set<String> upgradedSIFiles = new HashSet<String>();
 
     try {
-      segnOutput = new ChecksumIndexOutput(directory.createOutput(segmentFileName, IOContext.DEFAULT));
+      segnOutput = new ChecksumIndexOutput(directory.createOutput(segmentsFileName, IOContext.DEFAULT));
       CodecUtil.writeHeader(segnOutput, "segments", VERSION_40);
       segnOutput.writeLong(version); 
       segnOutput.writeInt(counter); // write counter
@@ -373,9 +376,29 @@ public final class SegmentInfos implemen
         // "ugprade" to write the .si file for it:
         String version = si.getVersion();
         if (version == null || StringHelper.getVersionComparator().compare(version, "4.0") < 0) {
-          String fileName = IndexFileNames.segmentFileName(si.name, "", Lucene3xSegmentInfoFormat.UPGRADED_SI_EXTENSION);
-          if (!directory.fileExists(fileName)) {
-            upgradedSIFiles.add(write3xInfo(directory, si, IOContext.DEFAULT));
+
+          if (!segmentWasUpgraded(directory, si)) {
+
+            final String segmentFileName = write3xInfo(directory, si, IOContext.DEFAULT);
+            upgradedSIFiles.add(segmentFileName);
+            directory.sync(Collections.singletonList(segmentFileName));
+
+            String markerFileName = IndexFileNames.segmentFileName(si.name, "upgraded", Lucene3xSegmentInfoFormat.UPGRADED_SI_EXTENSION);
+
+            // Write separate marker file indicating upgrade
+            // is completed.  This way, if there is a JVM
+            // kill/crash, OS crash, power loss, etc. while
+            // writing the upgraded file, the marker file
+            // will be missing:
+            si.addFile(markerFileName);
+            IndexOutput out = directory.createOutput(markerFileName, IOContext.DEFAULT);
+            try {
+              CodecUtil.writeHeader(out, SEGMENT_INFO_UPGRADE_CODEC, SEGMENT_INFO_UPGRADE_VERSION);
+            } finally {
+              out.close();
+            }
+            upgradedSIFiles.add(markerFileName);
+            directory.sync(Collections.singletonList(markerFileName));
           }
         }
       }
@@ -399,7 +422,7 @@ public final class SegmentInfos implemen
         try {
           // Try not to leave a truncated segments_N file in
           // the index:
-          directory.deleteFile(segmentFileName);
+          directory.deleteFile(segmentsFileName);
         } catch (Throwable t) {
           // Suppress so we keep throwing the original exception
         }
@@ -407,6 +430,27 @@ public final class SegmentInfos implemen
     }
   }
 
+  private static boolean segmentWasUpgraded(Directory directory, SegmentInfo si) {
+    // Check marker file:
+    String markerFileName = IndexFileNames.segmentFileName(si.name, "upgraded", Lucene3xSegmentInfoFormat.UPGRADED_SI_EXTENSION);
+    IndexInput in = null;
+    try {
+      in = directory.openInput(markerFileName, IOContext.READONCE);
+      if (CodecUtil.checkHeader(in, SEGMENT_INFO_UPGRADE_CODEC, SEGMENT_INFO_UPGRADE_VERSION, SEGMENT_INFO_UPGRADE_VERSION) == 0) {
+        return true;
+      }
+    } catch (IOException ioe) {
+      // Ignore: if something is wrong w/ the marker file,
+      // we will just upgrade again
+    } finally {
+      if (in != null) {
+        IOUtils.closeWhileHandlingException(in);
+      }
+    }
+    return false;
+  }
+
+
   @Deprecated
   public static String write3xInfo(Directory dir, SegmentInfo si, IOContext context) throws IOException {