77
88package  org .elasticsearch .xpack .lucene .bwc .codecs ;
99
10- import  org .apache .lucene .backward_codecs .lucene70 .Lucene70Codec ;
1110import  org .apache .lucene .codecs .Codec ;
1211import  org .apache .lucene .codecs .FieldInfosFormat ;
1312import  org .apache .lucene .codecs .FieldsConsumer ;
1817import  org .apache .lucene .codecs .PostingsFormat ;
1918import  org .apache .lucene .codecs .SegmentInfoFormat ;
2019import  org .apache .lucene .codecs .TermVectorsFormat ;
20+ import  org .apache .lucene .codecs .perfield .PerFieldPostingsFormat ;
2121import  org .apache .lucene .index .FieldInfo ;
2222import  org .apache .lucene .index .FieldInfos ;
2323import  org .apache .lucene .index .Fields ;
2727import  org .apache .lucene .index .Terms ;
2828import  org .apache .lucene .store .Directory ;
2929import  org .apache .lucene .store .IOContext ;
30+ import  org .apache .lucene .util .Version ;
3031import  org .elasticsearch .xpack .lucene .bwc .codecs .lucene70 .BWCLucene70Codec ;
32+ import  org .elasticsearch .xpack .lucene .bwc .codecs .lucene80 .BWCLucene80Codec ;
33+ import  org .elasticsearch .xpack .lucene .bwc .codecs .lucene84 .BWCLucene84Codec ;
34+ import  org .elasticsearch .xpack .lucene .bwc .codecs .lucene86 .BWCLucene86Codec ;
35+ import  org .elasticsearch .xpack .lucene .bwc .codecs .lucene87 .BWCLucene87Codec ;
3136
3237import  java .io .IOException ;
3338import  java .util .ArrayList ;
3944 */ 
4045public  abstract  class  BWCCodec  extends  Codec  {
4146
47+     private  final  FieldInfosFormat  fieldInfosFormat ;
48+     private  final  SegmentInfoFormat  segmentInfosFormat ;
49+     private  final  PostingsFormat  postingsFormat ;
50+ 
4251    protected  BWCCodec (String  name ) {
4352        super (name );
44-     }
4553
46-     @ Override 
47-     public  NormsFormat  normsFormat () {
48-         throw  new  UnsupportedOperationException ();
49-     }
54+         this .fieldInfosFormat  = new  FieldInfosFormat () {
55+             final  FieldInfosFormat  wrappedFormat  = originalFieldInfosFormat ();
5056
51-     @ Override 
52-     public  TermVectorsFormat  termVectorsFormat () {
53-         throw  new  UnsupportedOperationException ();
54-     }
57+             @ Override 
58+             public  FieldInfos  read (Directory  directory , SegmentInfo  segmentInfo , String  segmentSuffix , IOContext  iocontext )
59+                 throws  IOException  {
60+                 return  filterFields (wrappedFormat .read (directory , segmentInfo , segmentSuffix , iocontext ));
61+             }
5562
56-     @ Override 
57-     public  KnnVectorsFormat  knnVectorsFormat () {
58-         throw  new  UnsupportedOperationException ();
59-     }
63+             @ Override 
64+             public  void  write (Directory  directory , SegmentInfo  segmentInfo , String  segmentSuffix , FieldInfos  infos , IOContext  context )
65+                 throws  IOException  {
66+                 wrappedFormat .write (directory , segmentInfo , segmentSuffix , infos , context );
67+             }
68+         };
69+ 
70+         this .segmentInfosFormat  = new  SegmentInfoFormat () {
71+             final  SegmentInfoFormat  wrappedFormat  = originalSegmentInfoFormat ();
6072
61-     protected  static  SegmentInfoFormat  wrap (SegmentInfoFormat  wrapped ) {
62-         return  new  SegmentInfoFormat () {
6373            @ Override 
6474            public  SegmentInfo  read (Directory  directory , String  segmentName , byte [] segmentID , IOContext  context ) throws  IOException  {
65-                 return  wrap (wrapped .read (directory , segmentName , segmentID , context ));
75+                 return  wrap (wrappedFormat .read (directory , segmentName , segmentID , context ));
6676            }
6777
6878            @ Override 
6979            public  void  write (Directory  dir , SegmentInfo  info , IOContext  ioContext ) throws  IOException  {
70-                 wrapped .write (dir , info , ioContext );
80+                 wrappedFormat .write (dir , info , ioContext );
7181            }
7282        };
73-     }
7483
75-     protected  static  FieldInfosFormat  wrap (FieldInfosFormat  wrapped ) {
76-         return  new  FieldInfosFormat () {
84+         this .postingsFormat  = new  PerFieldPostingsFormat () {
7785            @ Override 
78-             public  FieldInfos  read (Directory  directory , SegmentInfo  segmentInfo , String  segmentSuffix , IOContext  iocontext )
79-                 throws  IOException  {
80-                 return  filterFields (wrapped .read (directory , segmentInfo , segmentSuffix , iocontext ));
81-             }
82- 
83-             @ Override 
84-             public  void  write (Directory  directory , SegmentInfo  segmentInfo , String  segmentSuffix , FieldInfos  infos , IOContext  context )
85-                 throws  IOException  {
86-                 wrapped .write (directory , segmentInfo , segmentSuffix , infos , context );
86+             public  PostingsFormat  getPostingsFormatForField (String  field ) {
87+                 throw  new  UnsupportedOperationException ("Old codecs can't be used for writing" );
8788            }
8889        };
8990    }
9091
92+     @ Override 
93+     public  final  FieldInfosFormat  fieldInfosFormat () {
94+         return  fieldInfosFormat ;
95+     }
96+ 
97+     @ Override 
98+     public  final  SegmentInfoFormat  segmentInfoFormat () {
99+         return  segmentInfosFormat ;
100+     }
101+ 
102+     @ Override 
103+     public  PostingsFormat  postingsFormat () {
104+         return  postingsFormat ;
105+     }
106+ 
107+     /** 
108+      * This method is not supported for archive indices and older codecs and will always throw an {@link UnsupportedOperationException}. 
109+      * This method is never called in practice, as we rewrite field infos to override the info about which features are present in 
110+      * the index. Even if norms are present, field info lies about it. 
111+      * 
112+      * @return nothing, as this method always throws an exception 
113+      * @throws UnsupportedOperationException always thrown to indicate that this method is not supported 
114+      */ 
115+     @ Override 
116+     public  final  NormsFormat  normsFormat () {
117+         throw  new  UnsupportedOperationException ();
118+     }
119+ 
120+     /** 
121+      * This method is not supported for archive indices and older codecs and will always throw an {@link UnsupportedOperationException}. 
122+      * This method is never called in practice, as we rewrite field infos to override the info about which features are present in 
123+      * the index. Even if term vectors are present, field info lies about it. 
124+      * 
125+      * @return nothing, as this method always throws an exception 
126+      * @throws UnsupportedOperationException always thrown to indicate that this method is not supported 
127+      */ 
128+     @ Override 
129+     public  final  TermVectorsFormat  termVectorsFormat () {
130+         throw  new  UnsupportedOperationException ();
131+     }
132+ 
133+     /** 
134+      * This method is not supported for archive indices and older codecs and will always throw an {@link UnsupportedOperationException}. 
135+      * 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. 
136+      * 
137+      * @return nothing, as this method always throws an exception 
138+      * @throws UnsupportedOperationException always thrown to indicate that this method is not supported 
139+      */ 
140+     @ Override 
141+     public  final  KnnVectorsFormat  knnVectorsFormat () {
142+         throw  new  UnsupportedOperationException ();
143+     }
144+ 
145+     /** 
146+      * Returns the original {@link SegmentInfoFormat} used by this codec. 
147+      * This method should be implemented by subclasses to provide the specific 
148+      * {@link SegmentInfoFormat} that this codec is intended to use. 
149+      * 
150+      * @return the original {@link SegmentInfoFormat} used by this codec 
151+      */ 
152+     protected  abstract  SegmentInfoFormat  originalSegmentInfoFormat ();
153+ 
154+     /** 
155+      * Returns the original {@link FieldInfosFormat} used by this codec. 
156+      * This method should be implemented by subclasses to provide the specific 
157+      * {@link FieldInfosFormat} that this codec is intended to use. 
158+      * 
159+      * @return the original {@link FieldInfosFormat} used by this codec 
160+      */ 
161+     protected  abstract  FieldInfosFormat  originalFieldInfosFormat ();
162+ 
91163    // mark all fields as no term vectors, no norms, no payloads, and no vectors. 
92164    private  static  FieldInfos  filterFields (FieldInfos  fieldInfos ) {
93165        List <FieldInfo > fieldInfoCopy  = new  ArrayList <>(fieldInfos .size ());
@@ -119,15 +191,14 @@ private static FieldInfos filterFields(FieldInfos fieldInfos) {
119191    }
120192
121193    public  static  SegmentInfo  wrap (SegmentInfo  segmentInfo ) {
122-         // special handling for Lucene70Codec (which is currently bundled with Lucene) 
123-         // Use BWCLucene70Codec instead as that one extends BWCCodec (similar to all other older codecs) 
124-         final  Codec  codec  = segmentInfo .getCodec () instanceof  Lucene70Codec  ? new  BWCLucene70Codec () : segmentInfo .getCodec ();
194+         Codec  codec  = getBackwardCompatibleCodec (segmentInfo .getCodec ());
195+ 
125196        final  SegmentInfo  segmentInfo1  = new  SegmentInfo (
126197            segmentInfo .dir ,
127198            // Use Version.LATEST instead of original version, otherwise SegmentCommitInfo will bark when processing (N-1 limitation) 
128199            // TODO: perhaps store the original version information in attributes so that we can retrieve it later when needed? 
129-             org . apache . lucene . util . Version .LATEST ,
130-             org . apache . lucene . util . Version .LATEST ,
200+             Version .LATEST ,
201+             Version .LATEST ,
131202            segmentInfo .name ,
132203            segmentInfo .maxDoc (),
133204            segmentInfo .getUseCompoundFile (),
@@ -142,6 +213,28 @@ public static SegmentInfo wrap(SegmentInfo segmentInfo) {
142213        return  segmentInfo1 ;
143214    }
144215
216+     /** 
217+      * Returns a backward-compatible codec for the given codec. If the codec is one of the known Lucene 8.x codecs, 
218+      * it returns a corresponding read-only backward-compatible codec. Otherwise, it returns the original codec. 
219+      * Lucene 8.x codecs are still shipped with the current version of Lucene. 
220+      * Earlier codecs we are providing directly they will also be read-only backward-compatible, but they don't require the renaming. 
221+      * 
222+      * This switch is only for indices created in ES 6.x, later written into in ES 7.x (Lucene 8.x). Indices created 
223+      * in ES 7.x can be read directly by ES if marked read-only, without going through archive indices. 
224+      */ 
225+     private  static  Codec  getBackwardCompatibleCodec (Codec  codec ) {
226+         if  (codec  == null ) return  null ;
227+ 
228+         return  switch  (codec .getClass ().getSimpleName ()) {
229+             case  "Lucene70Codec"  -> new  BWCLucene70Codec ();
230+             case  "Lucene80Codec"  -> new  BWCLucene80Codec ();
231+             case  "Lucene84Codec"  -> new  BWCLucene84Codec ();
232+             case  "Lucene86Codec"  -> new  BWCLucene86Codec ();
233+             case  "Lucene87Codec"  -> new  BWCLucene87Codec ();
234+             default  -> codec ;
235+         };
236+     }
237+ 
145238    /** 
146239     * In-memory postings format that shows no postings available. 
147240     */ 
0 commit comments