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