[ENGINE] Upgrade 3.x segments on engine startup #9899

Merged
merged 1 commit into from Feb 26, 2015

Projects

None yet

4 participants

@s1monw
Contributor
s1monw commented Feb 26, 2015

Upgrading 3.x segments have been proven to be error prone especially when it get's to
concurrency. Bugs like LUCENE-6287 cause index corrupting when segmetns are upgraded
concurrently to a merge. To play safe this commit upgrades pending segments without
merging etc. before the engine gets started up.

@s1monw
Contributor
s1monw commented Feb 26, 2015

@mikemccand can you take a look

@mikemccand mikemccand commented on an outdated diff Feb 26, 2015
...main/java/org/elasticsearch/common/lucene/Lucene.java
@@ -724,4 +726,45 @@ public void delete() {
throw new UnsupportedOperationException("This IndexCommit does not support deletions");
}
}
+
+ /**
+ * Retruns <code>true</code> iff the store contains an index that contains segments that where
@mikemccand
mikemccand Feb 26, 2015 Contributor

Retruns -> Returns

where -> were

@mikemccand mikemccand commented on an outdated diff Feb 26, 2015
...main/java/org/elasticsearch/common/lucene/Lucene.java
@@ -724,4 +726,45 @@ public void delete() {
throw new UnsupportedOperationException("This IndexCommit does not support deletions");
}
}
+
+ /**
+ * Retruns <code>true</code> iff the store contains an index that contains segments that where
+ * not upgraded to the lucene 4.x format.
+ */
+ public static boolean indexNeeds3xUpgrading(Directory directory) throws IOException {
+ try {
+ SegmentInfos si = Lucene.readSegmentInfos(directory);
+ for (SegmentCommitInfo info : si) {
+ Version version = info.info.getVersion();
+ if (version == null || version.onOrAfter(Version.LUCENE_4_0_0_ALPHA) == false) {
+ boolean upgraded = false;
+ final String markerFileName = IndexFileNames.segmentFileName(info.info.name, "upgraded", Lucene3xSegmentInfoFormat.UPGRADED_SI_EXTENSION);
+ for(String file : info.files()) {
@mikemccand
mikemccand Feb 26, 2015 Contributor

I think you can just do this?

if (info.files().contains(markerFileName) == false) {
  return true;
}
@mikemccand
mikemccand Feb 26, 2015 Contributor

Really you just need to look @ the first int of the segments_N ... if that's == CodecUtil.CODEC_MAGIC, the index was already upgraded to 4.0+. Then you don't need to step through each info.

@mikemccand mikemccand commented on an outdated diff Feb 26, 2015
...va/org/elasticsearch/index/engine/InternalEngine.java
@@ -1025,6 +1033,15 @@ public void warm(AtomicReader reader) throws IOException {
}
}
+ protected static void upgrade3xSegments(Store store) throws IOException {
+ store.incRef();
+ try {
+ Lucene.upgradeLucene3xSegments(store.directory());
@mikemccand
mikemccand Feb 26, 2015 Contributor

Can we somehow logger.info if we did in fact do the 3.x upgrade?

@kimchy kimchy commented on an outdated diff Feb 26, 2015
...main/java/org/elasticsearch/common/lucene/Lucene.java
+ upgraded = true;
+ break;
+ }
+ }
+ if (upgraded == false) {
+ return true;
+ }
+ }
+ }
+ return false;
+ } catch (IndexNotFoundException e) {
+ return false;
+ }
+ }
+
+ public static void upgradeLucene3xSegments(Directory directory) throws IOException {
@kimchy
kimchy Feb 26, 2015 Member

this method name might be confusing? it sounds like it will do a full upgrade, while we just need a non 3x commit point?

@s1monw
Contributor
s1monw commented Feb 26, 2015

@mikemccand @kimchy pushed a new commit

@mikemccand mikemccand commented on an outdated diff Feb 26, 2015
...main/java/org/elasticsearch/common/lucene/Lucene.java
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Upgrades the segments metadata of the index to match a lucene 4.x index format. In particular it ensures that each
+ * segment has a .si file even if it was written with lucene 3.x
+ */
+ public static boolean upgradeLucene3xSegmentsMetadata(Directory directory) throws IOException {
+ if (indexNeeds3xUpgrading(directory)) {
+ try (final IndexWriter iw = new IndexWriter(directory, new IndexWriterConfig(Version.LATEST, Lucene.STANDARD_ANALYZER)
+ .setMergePolicy(NoMergePolicy.INSTANCE)
+ .setOpenMode(IndexWriterConfig.OpenMode.APPEND))) {
+ Map<String, String> commitData = iw.getCommitData();
+ iw.setCommitData(commitData);
@mikemccand
mikemccand Feb 26, 2015 Contributor

Maybe add a comment that you do this to trick IW into committing when it thinks nothing changed :)

@mikemccand mikemccand commented on an outdated diff Feb 26, 2015
...main/java/org/elasticsearch/common/lucene/Lucene.java
@@ -724,4 +726,36 @@ public void delete() {
throw new UnsupportedOperationException("This IndexCommit does not support deletions");
}
}
+
+ /**
+ * Returns <code>true</code> iff the store contains an index that contains segments that were
+ * not upgraded to the lucene 4.x format.
+ */
+ public static boolean indexNeeds3xUpgrading(Directory directory) throws IOException {
@mikemccand
mikemccand Feb 26, 2015 Contributor

Maybe make this package private?

@mikemccand
Contributor

Left 2 minor comments else LGTM.

@s1monw
Contributor
s1monw commented Feb 26, 2015

cool thanks, I beefed up the test a bit and applied the feedback

@mikemccand
Contributor

LGTM

@s1monw s1monw [ENGINE] Upgrade 3.x segments on engine startup
Upgrading 3.x segments have been proven to be error prone especially when it get's to
concurrency. Bugs like LUCENE-6287 cause index corrupting when segmetns are upgraded
concurrently to a merge. To play safe this commit upgrades pending segments without
merging etc. before the engine gets started up.
f5b1ba4
@s1monw s1monw merged commit f5b1ba4 into elastic:1.x Feb 26, 2015

1 check passed

CLA Commit author is a member of Elasticsearch
Details
@clintongormley clintongormley added :Engine and removed review labels Mar 19, 2015
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment