Skip to content

Add API to mount a snapshot as a searchable index #53084

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
c847e03
Add API to mount a snapshot as a searchable index
dakrone Feb 26, 2020
0cd28a3
Update docstring for MountSearchableSnapshotRequest constructor
dakrone Mar 4, 2020
2bcab06
Remove extra line
dakrone Mar 4, 2020
000ee16
Wrap repository fetching in try/catch
dakrone Mar 4, 2020
74212e1
ConstructingObjectParser
DaveCTurner Mar 5, 2020
b4933e5
Tidy up transport action
DaveCTurner Mar 6, 2020
ff16586
Revert
DaveCTurner Mar 6, 2020
520673e
Fix up REST tests and a bit of a refactor
DaveCTurner Mar 6, 2020
4cbf27e
Move more code out of SearchableSnapshotRepository
DaveCTurner Mar 6, 2020
4ad409b
Move factory around
DaveCTurner Mar 6, 2020
f44d68f
Move settings etc.
DaveCTurner Mar 6, 2020
595a74f
Whitespace
DaveCTurner Mar 6, 2020
924a741
Less nullability
DaveCTurner Mar 6, 2020
fd9d858
Final
DaveCTurner Mar 6, 2020
7297b35
More tidy
DaveCTurner Mar 6, 2020
dae1d93
Rejig API shape
DaveCTurner Mar 6, 2020
366f456
Merge branch 'feature/searchable-snapshots' into ss-add-dedicated-res…
DaveCTurner Mar 6, 2020
96ab324
Merge branch 'feature/searchable-snapshots' into ss-add-dedicated-res…
DaveCTurner Mar 6, 2020
7b8e560
Not optional
DaveCTurner Mar 9, 2020
cca756e
Better description
DaveCTurner Mar 9, 2020
4a7588f
Remove ToXContent, we will do this later in the client
DaveCTurner Mar 9, 2020
dbe178f
Pass request directly to parser
DaveCTurner Mar 9, 2020
6d2e48c
Javadoc
DaveCTurner Mar 9, 2020
85ba301
Rename
DaveCTurner Mar 9, 2020
414e830
Expand TODO comment
DaveCTurner Mar 9, 2020
e9945d5
Merge branch 'feature/searchable-snapshots' into ss-add-dedicated-res…
DaveCTurner Mar 9, 2020
b44d220
Merge branch 'feature/searchable-snapshots' into ss-add-dedicated-res…
DaveCTurner Mar 9, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -51,15 +51,6 @@ setup:
indices.delete:
index: docs

- do:
snapshot.create_repository:
repository: repository-searchable-snapshots
body:
type: searchable
settings:
delegate_type: fs
location: "repository-fs"

---
teardown:

Expand All @@ -73,10 +64,6 @@ teardown:
snapshot.delete_repository:
repository: repository-fs

- do:
snapshot.delete_repository:
repository: repository-searchable-snapshots

---
"Clear searchable snapshots cache":
- skip:
Expand Down Expand Up @@ -116,10 +103,12 @@ teardown:
- match: { error.root_cause.0.reason: "No searchable snapshots indices found" }

- do:
snapshot.restore:
repository: repository-searchable-snapshots
searchable_snapshots.mount:
repository: repository-fs
snapshot: snapshot
wait_for_completion: true
body:
index: docs

- match: { snapshot.snapshot: snapshot }
- match: { snapshot.shards.failed: 0 }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,21 +102,12 @@ teardown:
- match: { error.root_cause.0.reason: "No searchable snapshots indices found" }

- do:
snapshot.create_repository:
repository: repository-searchable-snapshots
body:
type: searchable
settings:
delegate_type: fs
location: "repository-fs"

- match: { acknowledged: true }

- do:
snapshot.restore:
repository: repository-searchable-snapshots
searchable_snapshots.mount:
repository: repository-fs
snapshot: snapshot
wait_for_completion: true
body:
index: docs

- match: { snapshot.snapshot: snapshot }
- match: { snapshot.shards.failed: 0 }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
package org.elasticsearch.xpack.searchablesnapshots;
package org.elasticsearch.index.store;

import org.apache.lucene.store.ByteBuffersDirectory;
import org.apache.lucene.store.Directory;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
*/
package org.elasticsearch.index.store;

import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.index.NoMergePolicy;
import org.apache.lucene.store.BaseDirectory;
import org.apache.lucene.store.BufferedIndexInput;
import org.apache.lucene.store.Directory;
Expand All @@ -13,14 +16,36 @@
import org.apache.lucene.store.IndexOutput;
import org.apache.lucene.store.SingleInstanceLockFactory;
import org.elasticsearch.common.blobstore.BlobContainer;
import org.elasticsearch.common.lucene.Lucene;
import org.elasticsearch.index.IndexSettings;
import org.elasticsearch.index.seqno.SequenceNumbers;
import org.elasticsearch.index.shard.ShardPath;
import org.elasticsearch.index.snapshots.blobstore.BlobStoreIndexShardSnapshot;
import org.elasticsearch.index.snapshots.blobstore.BlobStoreIndexShardSnapshot.FileInfo;
import org.elasticsearch.index.translog.Translog;
import org.elasticsearch.repositories.IndexId;
import org.elasticsearch.repositories.RepositoriesService;
import org.elasticsearch.repositories.Repository;
import org.elasticsearch.repositories.blobstore.BlobStoreRepository;
import org.elasticsearch.snapshots.SnapshotId;
import org.elasticsearch.xpack.searchablesnapshots.cache.CacheDirectory;
import org.elasticsearch.xpack.searchablesnapshots.cache.CacheService;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.file.Path;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.function.LongSupplier;

import static org.elasticsearch.xpack.searchablesnapshots.SearchableSnapshots.SNAPSHOT_CACHE_ENABLED_SETTING;
import static org.elasticsearch.xpack.searchablesnapshots.SearchableSnapshots.SNAPSHOT_INDEX_ID_SETTING;
import static org.elasticsearch.xpack.searchablesnapshots.SearchableSnapshots.SNAPSHOT_REPOSITORY_SETTING;
import static org.elasticsearch.xpack.searchablesnapshots.SearchableSnapshots.SNAPSHOT_SNAPSHOT_ID_SETTING;
import static org.elasticsearch.xpack.searchablesnapshots.SearchableSnapshots.SNAPSHOT_SNAPSHOT_NAME_SETTING;

/**
* Implementation of {@link Directory} that exposes files from a snapshot as a Lucene directory. Because snapshot are immutable this
Expand All @@ -38,7 +63,7 @@ public class SearchableSnapshotDirectory extends BaseDirectory {
private final BlobStoreIndexShardSnapshot snapshot;
private final BlobContainer blobContainer;

public SearchableSnapshotDirectory(final BlobStoreIndexShardSnapshot snapshot, final BlobContainer blobContainer) {
SearchableSnapshotDirectory(final BlobStoreIndexShardSnapshot snapshot, final BlobContainer blobContainer) {
super(new SingleInstanceLockFactory());
this.snapshot = Objects.requireNonNull(snapshot);
this.blobContainer = Objects.requireNonNull(blobContainer);
Expand Down Expand Up @@ -121,4 +146,52 @@ public void rename(String source, String dest) {
private static UnsupportedOperationException unsupportedException() {
return new UnsupportedOperationException("Searchable snapshot directory does not support this operation");
}

public static Directory create(RepositoriesService repositories,
CacheService cache,
IndexSettings indexSettings,
ShardPath shardPath,
LongSupplier currentTimeNanosSupplier) throws IOException {

final Repository repository = repositories.repository(SNAPSHOT_REPOSITORY_SETTING.get(indexSettings.getSettings()));
if (repository instanceof BlobStoreRepository == false) {
throw new IllegalArgumentException("Repository [" + repository + "] is not searchable");
}
final BlobStoreRepository blobStoreRepository = (BlobStoreRepository) repository;

final IndexId indexId = new IndexId(indexSettings.getIndex().getName(), SNAPSHOT_INDEX_ID_SETTING.get(indexSettings.getSettings()));
final BlobContainer blobContainer = blobStoreRepository.shardContainer(indexId, shardPath.getShardId().id());

final SnapshotId snapshotId = new SnapshotId(SNAPSHOT_SNAPSHOT_NAME_SETTING.get(indexSettings.getSettings()),
SNAPSHOT_SNAPSHOT_ID_SETTING.get(indexSettings.getSettings()));
final BlobStoreIndexShardSnapshot snapshot = blobStoreRepository.loadShardSnapshot(blobContainer, snapshotId);

Directory directory = new SearchableSnapshotDirectory(snapshot, blobContainer);
if (SNAPSHOT_CACHE_ENABLED_SETTING.get(indexSettings.getSettings())) {
final Path cacheDir = shardPath.getDataPath().resolve("snapshots").resolve(snapshotId.getUUID());
directory = new CacheDirectory(directory, cache, cacheDir, snapshotId, indexId, shardPath.getShardId(),
currentTimeNanosSupplier);
}
directory = new InMemoryNoOpCommitDirectory(directory);

final IndexWriterConfig indexWriterConfig = new IndexWriterConfig(null)
.setSoftDeletesField(Lucene.SOFT_DELETES_FIELD)
.setMergePolicy(NoMergePolicy.INSTANCE);

try (IndexWriter indexWriter = new IndexWriter(directory, indexWriterConfig)) {
final Map<String, String> userData = new HashMap<>();
indexWriter.getLiveCommitData().forEach(e -> userData.put(e.getKey(), e.getValue()));

final String translogUUID = Translog.createEmptyTranslog(shardPath.resolveTranslog(),
Long.parseLong(userData.get(SequenceNumbers.LOCAL_CHECKPOINT_KEY)),
shardPath.getShardId(), 0L);

userData.put(Translog.TRANSLOG_UUID_KEY, translogUUID);
indexWriter.setLiveCommitData(userData.entrySet());
indexWriter.commit();
}

return directory;
}

}

This file was deleted.

Loading