1717import org .apache .lucene .codecs .PostingsFormat ;
1818import org .apache .lucene .codecs .SegmentInfoFormat ;
1919import org .apache .lucene .codecs .TermVectorsFormat ;
20+ import org .apache .lucene .codecs .perfield .PerFieldPostingsFormat ;
2021import org .apache .lucene .index .FieldInfo ;
2122import org .apache .lucene .index .FieldInfos ;
2223import org .apache .lucene .index .Fields ;
2627import org .apache .lucene .index .Terms ;
2728import org .apache .lucene .store .Directory ;
2829import org .apache .lucene .store .IOContext ;
30+ import org .apache .lucene .util .Version ;
31+ import org .elasticsearch .core .UpdateForV10 ;
32+ import org .elasticsearch .xpack .lucene .bwc .codecs .lucene70 .BWCLucene70Codec ;
33+ import org .elasticsearch .xpack .lucene .bwc .codecs .lucene80 .BWCLucene80Codec ;
34+ import org .elasticsearch .xpack .lucene .bwc .codecs .lucene84 .BWCLucene84Codec ;
35+ import org .elasticsearch .xpack .lucene .bwc .codecs .lucene86 .BWCLucene86Codec ;
36+ import org .elasticsearch .xpack .lucene .bwc .codecs .lucene87 .BWCLucene87Codec ;
2937
3038import java .io .IOException ;
3139import java .util .ArrayList ;
3745 */
3846public abstract class BWCCodec extends Codec {
3947
48+ private final FieldInfosFormat fieldInfosFormat ;
49+ private final SegmentInfoFormat segmentInfosFormat ;
50+ private final PostingsFormat postingsFormat ;
51+
4052 protected BWCCodec (String name ) {
4153 super (name );
42- }
4354
44- @ Override
45- public NormsFormat normsFormat () {
46- throw new UnsupportedOperationException ();
47- }
55+ this .fieldInfosFormat = new FieldInfosFormat () {
56+ final FieldInfosFormat wrappedFormat = originalFieldInfosFormat ();
4857
49- @ Override
50- public TermVectorsFormat termVectorsFormat () {
51- throw new UnsupportedOperationException ();
52- }
58+ @ Override
59+ public FieldInfos read (Directory directory , SegmentInfo segmentInfo , String segmentSuffix , IOContext iocontext )
60+ throws IOException {
61+ return filterFields (wrappedFormat .read (directory , segmentInfo , segmentSuffix , iocontext ));
62+ }
5363
54- @ Override
55- public KnnVectorsFormat knnVectorsFormat () {
56- throw new UnsupportedOperationException ();
57- }
64+ @ Override
65+ public void write (Directory directory , SegmentInfo segmentInfo , String segmentSuffix , FieldInfos infos , IOContext context )
66+ throws IOException {
67+ wrappedFormat .write (directory , segmentInfo , segmentSuffix , infos , context );
68+ }
69+ };
70+
71+ this .segmentInfosFormat = new SegmentInfoFormat () {
72+ final SegmentInfoFormat wrappedFormat = originalSegmentInfoFormat ();
5873
59- protected static SegmentInfoFormat wrap (SegmentInfoFormat wrapped ) {
60- return new SegmentInfoFormat () {
6174 @ Override
6275 public SegmentInfo read (Directory directory , String segmentName , byte [] segmentID , IOContext context ) throws IOException {
63- return wrap (wrapped .read (directory , segmentName , segmentID , context ));
76+ return wrap (wrappedFormat .read (directory , segmentName , segmentID , context ));
6477 }
6578
6679 @ Override
6780 public void write (Directory dir , SegmentInfo info , IOContext ioContext ) throws IOException {
68- wrapped .write (dir , info , ioContext );
81+ wrappedFormat .write (dir , info , ioContext );
6982 }
7083 };
71- }
7284
73- protected static FieldInfosFormat wrap (FieldInfosFormat wrapped ) {
74- return new FieldInfosFormat () {
85+ this .postingsFormat = new PerFieldPostingsFormat () {
7586 @ Override
76- public FieldInfos read (Directory directory , SegmentInfo segmentInfo , String segmentSuffix , IOContext iocontext )
77- throws IOException {
78- return filterFields (wrapped .read (directory , segmentInfo , segmentSuffix , iocontext ));
79- }
80-
81- @ Override
82- public void write (Directory directory , SegmentInfo segmentInfo , String segmentSuffix , FieldInfos infos , IOContext context )
83- throws IOException {
84- wrapped .write (directory , segmentInfo , segmentSuffix , infos , context );
87+ public PostingsFormat getPostingsFormatForField (String field ) {
88+ throw new UnsupportedOperationException ("Old codecs can't be used for writing" );
8589 }
8690 };
8791 }
8892
93+ @ Override
94+ public final FieldInfosFormat fieldInfosFormat () {
95+ return fieldInfosFormat ;
96+ }
97+
98+ @ Override
99+ public final SegmentInfoFormat segmentInfoFormat () {
100+ return segmentInfosFormat ;
101+ }
102+
103+ @ Override
104+ public PostingsFormat postingsFormat () {
105+ return postingsFormat ;
106+ }
107+
108+ /**
109+ * This method is not supported for archive indices and older codecs and will always throw an {@link UnsupportedOperationException}.
110+ * This method is never called in practice, as we rewrite field infos to override the info about which features are present in
111+ * the index. Even if norms are present, field info lies about it.
112+ *
113+ * @return nothing, as this method always throws an exception
114+ * @throws UnsupportedOperationException always thrown to indicate that this method is not supported
115+ */
116+ @ Override
117+ public final NormsFormat normsFormat () {
118+ throw new UnsupportedOperationException ();
119+ }
120+
121+ /**
122+ * This method is not supported for archive indices and older codecs and will always throw an {@link UnsupportedOperationException}.
123+ * This method is never called in practice, as we rewrite field infos to override the info about which features are present in
124+ * the index. Even if term vectors are present, field info lies about it.
125+ *
126+ * @return nothing, as this method always throws an exception
127+ * @throws UnsupportedOperationException always thrown to indicate that this method is not supported
128+ */
129+ @ Override
130+ public final TermVectorsFormat termVectorsFormat () {
131+ throw new UnsupportedOperationException ();
132+ }
133+
134+ /**
135+ * This method is not supported for archive indices and older codecs and will always throw an {@link UnsupportedOperationException}.
136+ * The knn vectors can't be present because it is not supported yet in any of the lucene versions that we support for archive indices.
137+ *
138+ * @return nothing, as this method always throws an exception
139+ * @throws UnsupportedOperationException always thrown to indicate that this method is not supported
140+ */
141+ @ Override
142+ public final KnnVectorsFormat knnVectorsFormat () {
143+ throw new UnsupportedOperationException ();
144+ }
145+
146+ /**
147+ * Returns the original {@link SegmentInfoFormat} used by this codec.
148+ * This method should be implemented by subclasses to provide the specific
149+ * {@link SegmentInfoFormat} that this codec is intended to use.
150+ *
151+ * @return the original {@link SegmentInfoFormat} used by this codec
152+ */
153+ protected abstract SegmentInfoFormat originalSegmentInfoFormat ();
154+
155+ /**
156+ * Returns the original {@link FieldInfosFormat} used by this codec.
157+ * This method should be implemented by subclasses to provide the specific
158+ * {@link FieldInfosFormat} that this codec is intended to use.
159+ *
160+ * @return the original {@link FieldInfosFormat} used by this codec
161+ */
162+ protected abstract FieldInfosFormat originalFieldInfosFormat ();
163+
89164 // mark all fields as no term vectors, no norms, no payloads, and no vectors.
90165 private static FieldInfos filterFields (FieldInfos fieldInfos ) {
91166 List <FieldInfo > fieldInfoCopy = new ArrayList <>(fieldInfos .size ());
@@ -118,13 +193,14 @@ private static FieldInfos filterFields(FieldInfos fieldInfos) {
118193 }
119194
120195 public static SegmentInfo wrap (SegmentInfo segmentInfo ) {
121- final Codec codec = segmentInfo .getCodec ();
196+ Codec codec = getBackwardCompatibleCodec (segmentInfo .getCodec ());
197+
122198 final SegmentInfo segmentInfo1 = new SegmentInfo (
123199 segmentInfo .dir ,
124200 // Use Version.LATEST instead of original version, otherwise SegmentCommitInfo will bark when processing (N-1 limitation)
125201 // TODO: perhaps store the original version information in attributes so that we can retrieve it later when needed?
126- org . apache . lucene . util . Version .LATEST ,
127- org . apache . lucene . util . Version .LATEST ,
202+ Version .LATEST ,
203+ Version .LATEST ,
128204 segmentInfo .name ,
129205 segmentInfo .maxDoc (),
130206 segmentInfo .getUseCompoundFile (),
@@ -139,6 +215,29 @@ public static SegmentInfo wrap(SegmentInfo segmentInfo) {
139215 return segmentInfo1 ;
140216 }
141217
218+ /**
219+ * Returns a backward-compatible codec for the given codec. If the codec is one of the known Lucene 8.x codecs,
220+ * it returns a corresponding read-only backward-compatible codec. Otherwise, it returns the original codec.
221+ * Lucene 8.x codecs are still shipped with the current version of Lucene.
222+ * Earlier codecs we are providing directly they will also be read-only backward-compatible, but they don't require the renaming.
223+ *
224+ * This switch is only for indices created in ES 6.x, later written into in ES 7.x (Lucene 8.x). Indices created
225+ * in ES 7.x can be read directly by ES if marked read-only, without going through archive indices.
226+ */
227+ @ UpdateForV10 (owner = UpdateForV10 .Owner .SEARCH_FOUNDATIONS )
228+ private static Codec getBackwardCompatibleCodec (Codec codec ) {
229+ if (codec == null ) return null ;
230+
231+ return switch (codec .getClass ().getSimpleName ()) {
232+ case "Lucene70Codec" -> new BWCLucene70Codec ();
233+ case "Lucene80Codec" -> new BWCLucene80Codec ();
234+ case "Lucene84Codec" -> new BWCLucene84Codec ();
235+ case "Lucene86Codec" -> new BWCLucene86Codec ();
236+ case "Lucene87Codec" -> new BWCLucene87Codec ();
237+ default -> codec ;
238+ };
239+ }
240+
142241 /**
143242 * In-memory postings format that shows no postings available.
144243 */
0 commit comments