1111import org .apache .logging .log4j .LogManager ;
1212import org .apache .logging .log4j .Logger ;
1313import org .apache .logging .log4j .message .ParameterizedMessage ;
14+ import org .apache .lucene .index .SegmentInfos ;
15+ import org .apache .lucene .store .BaseDirectory ;
16+ import org .apache .lucene .store .IOContext ;
17+ import org .apache .lucene .store .IndexInput ;
18+ import org .apache .lucene .store .IndexOutput ;
19+ import org .apache .lucene .store .SingleInstanceLockFactory ;
20+ import org .apache .lucene .util .BytesRef ;
1421import org .elasticsearch .action .ActionListener ;
1522import org .elasticsearch .action .admin .cluster .snapshots .get .shard .GetShardSnapshotAction ;
1623import org .elasticsearch .action .admin .cluster .snapshots .get .shard .GetShardSnapshotRequest ;
2229import org .elasticsearch .cluster .service .ClusterService ;
2330import org .elasticsearch .common .blobstore .BlobContainer ;
2431import org .elasticsearch .common .inject .Inject ;
32+ import org .elasticsearch .common .lucene .Lucene ;
33+ import org .elasticsearch .common .lucene .store .ByteArrayIndexInput ;
2534import org .elasticsearch .index .shard .ShardId ;
2635import org .elasticsearch .index .snapshots .blobstore .BlobStoreIndexShardSnapshot ;
36+ import org .elasticsearch .index .store .StoreFileMetadata ;
2737import org .elasticsearch .repositories .RepositoriesService ;
2838import org .elasticsearch .repositories .Repository ;
2939import org .elasticsearch .repositories .ShardSnapshotInfo ;
3040import org .elasticsearch .repositories .blobstore .BlobStoreRepository ;
3141import org .elasticsearch .snapshots .Snapshot ;
3242import org .elasticsearch .threadpool .ThreadPool ;
3343
44+ import java .io .IOException ;
45+ import java .util .Collection ;
3446import java .util .List ;
47+ import java .util .Map ;
3548import java .util .Optional ;
49+ import java .util .Set ;
50+ import java .util .function .Function ;
3651import java .util .stream .Collectors ;
3752
3853import static org .elasticsearch .indices .recovery .RecoverySettings .SNAPSHOT_RECOVERIES_SUPPORTED_VERSION ;
@@ -108,7 +123,16 @@ private Optional<ShardSnapshot> fetchSnapshotFiles(GetShardSnapshotResponse shar
108123 BlobStoreIndexShardSnapshot blobStoreIndexShardSnapshot =
109124 blobStoreRepository .loadShardSnapshot (blobContainer , snapshot .getSnapshotId ());
110125
111- return Optional .of (new ShardSnapshot (latestShardSnapshot , blobStoreIndexShardSnapshot .indexFiles ()));
126+ Map <String , StoreFileMetadata > snapshotFiles = blobStoreIndexShardSnapshot .indexFiles ()
127+ .stream ()
128+ .map (BlobStoreIndexShardSnapshot .FileInfo ::metadata )
129+ .collect (Collectors .toMap (StoreFileMetadata ::name , Function .identity ()));
130+
131+ InMemoryDirectory directory = new InMemoryDirectory (snapshotFiles );
132+ SegmentInfos segmentCommitInfos = Lucene .readSegmentInfos (directory );
133+ Map <String , String > userData = segmentCommitInfos .userData ;
134+
135+ return Optional .of (new ShardSnapshot (latestShardSnapshot , blobStoreIndexShardSnapshot .indexFiles (), userData ));
112136 } catch (Exception e ) {
113137 logger .warn (new ParameterizedMessage ("Unable to fetch shard snapshot files for {}" , latestShardSnapshot ), e );
114138 return Optional .empty ();
@@ -118,4 +142,84 @@ private Optional<ShardSnapshot> fetchSnapshotFiles(GetShardSnapshotResponse shar
118142 protected boolean masterSupportsFetchingLatestSnapshots () {
119143 return clusterService .state ().nodes ().getMinNodeVersion ().onOrAfter (SNAPSHOT_RECOVERIES_SUPPORTED_VERSION );
120144 }
145+
146+ static final class InMemoryDirectory extends BaseDirectory {
147+ private final Map <String , StoreFileMetadata > files ;
148+
149+ InMemoryDirectory (Map <String , StoreFileMetadata > files ) {
150+ super (new SingleInstanceLockFactory ());
151+ this .files = files ;
152+ }
153+
154+ @ Override
155+ public String [] listAll () {
156+ return files .keySet ().toArray (new String [0 ]);
157+ }
158+
159+ @ Override
160+ public IndexInput openInput (String name , IOContext context ) throws IOException {
161+ StoreFileMetadata storeFileMetadata = getStoreFileMetadata (name );
162+ if (storeFileMetadata .hashEqualsContents () == false ) {
163+ throw new IOException ("Unable to open " + name );
164+ }
165+
166+ final BytesRef data = storeFileMetadata .hash ();
167+ return new ByteArrayIndexInput (name , data .bytes , data .offset , data .length );
168+ }
169+
170+ @ Override
171+ public void deleteFile (String name ) {
172+ throw new UnsupportedOperationException ("this directory is read-only" );
173+ }
174+
175+ @ Override
176+ public long fileLength (String name ) throws IOException {
177+ final StoreFileMetadata storeFileMetadata = getStoreFileMetadata (name );
178+ return storeFileMetadata .length ();
179+ }
180+
181+
182+ @ Override
183+ public IndexOutput createOutput (String name , IOContext context ) {
184+ throw new UnsupportedOperationException ("this directory is read-only" );
185+ }
186+
187+ @ Override
188+ public IndexOutput createTempOutput (String prefix , String suffix , IOContext context ) {
189+ throw new UnsupportedOperationException ("this directory is read-only" );
190+ }
191+
192+ @ Override
193+ public void sync (Collection <String > names ) {
194+ throw new UnsupportedOperationException ("this directory is read-only" );
195+ }
196+
197+ @ Override
198+ public void syncMetaData () {
199+ throw new UnsupportedOperationException ("this directory is read-only" );
200+ }
201+
202+ @ Override
203+ public void rename (String source , String dest ) {
204+ throw new UnsupportedOperationException ("this directory is read-only" );
205+ }
206+
207+ @ Override
208+ public void close () {
209+ // no-op
210+ }
211+
212+ @ Override
213+ public Set <String > getPendingDeletions () {
214+ throw new UnsupportedOperationException ("this directory is read-only" );
215+ }
216+
217+ private StoreFileMetadata getStoreFileMetadata (String name ) throws IOException {
218+ final StoreFileMetadata storeFileMetadata = files .get (name );
219+ if (storeFileMetadata == null ) {
220+ throw new IOException ("Unable to find " + name );
221+ }
222+ return storeFileMetadata ;
223+ }
224+ }
121225}
0 commit comments