Skip to content

Commit 714c480

Browse files
tlrxDaveCTurner
andauthored
Add searchable snapshots cache directory (#50693)
This pull request adds a new CacheDirectory implementation which allows to cache ranges of bytes of Lucene files. This directory implementation uses a CacheService to retrieve and to read ranges of bytes from cached files stored on disk. The cached files are created as sparse files on disk and the availability of bytes ranges are tracked through a SparseFileTracker instance. Co-authored-by: David Turner <[email protected]>
1 parent ffc5a82 commit 714c480

File tree

10 files changed

+1724
-27
lines changed

10 files changed

+1724
-27
lines changed

x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/SearchableSnapshotRepository.java

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,11 @@
2727
import org.elasticsearch.repositories.Repository;
2828
import org.elasticsearch.repositories.blobstore.BlobStoreRepository;
2929
import org.elasticsearch.snapshots.SnapshotId;
30+
import org.elasticsearch.xpack.searchablesnapshots.cache.CacheDirectory;
31+
import org.elasticsearch.xpack.searchablesnapshots.cache.CacheService;
3032

3133
import java.io.IOException;
34+
import java.nio.file.Path;
3235
import java.util.HashMap;
3336
import java.util.Map;
3437
import java.util.function.Function;
@@ -53,6 +56,8 @@ public class SearchableSnapshotRepository extends FilterRepository {
5356
Setting.simpleString("index.store.snapshot.snapshot_uuid", Setting.Property.IndexScope, Setting.Property.PrivateIndex);
5457
public static final Setting<String> SNAPSHOT_INDEX_ID_SETTING =
5558
Setting.simpleString("index.store.snapshot.index_uuid", Setting.Property.IndexScope, Setting.Property.PrivateIndex);
59+
public static final Setting<Boolean> SNAPSHOT_CACHE_ENABLED_SETTING =
60+
Setting.boolSetting("index.store.snapshot.cache.enabled", true, Setting.Property.IndexScope);
5661

5762
public static final String SNAPSHOT_DIRECTORY_FACTORY_KEY = "snapshot";
5863

@@ -64,12 +69,12 @@ public class SearchableSnapshotRepository extends FilterRepository {
6469
public SearchableSnapshotRepository(Repository in) {
6570
super(in);
6671
if (in instanceof BlobStoreRepository == false) {
67-
throw new IllegalArgumentException("Repository [" + in + "] does not support searchable snapshots" );
72+
throw new IllegalArgumentException("Repository [" + in + "] does not support searchable snapshots");
6873
}
6974
blobStoreRepository = (BlobStoreRepository) in;
7075
}
7176

72-
private Directory makeDirectory(IndexSettings indexSettings, ShardPath shardPath) throws IOException {
77+
private Directory makeDirectory(IndexSettings indexSettings, ShardPath shardPath, CacheService cacheService) throws IOException {
7378

7479
IndexId indexId = new IndexId(indexSettings.getIndex().getName(), SNAPSHOT_INDEX_ID_SETTING.get(indexSettings.getSettings()));
7580
BlobContainer blobContainer = blobStoreRepository.shardContainer(indexId, shardPath.getShardId().id());
@@ -78,10 +83,14 @@ private Directory makeDirectory(IndexSettings indexSettings, ShardPath shardPath
7883
SNAPSHOT_SNAPSHOT_ID_SETTING.get(indexSettings.getSettings()));
7984
BlobStoreIndexShardSnapshot snapshot = blobStoreRepository.loadShardSnapshot(blobContainer, snapshotId);
8085

81-
final SearchableSnapshotDirectory searchableSnapshotDirectory = new SearchableSnapshotDirectory(snapshot, blobContainer);
82-
final InMemoryNoOpCommitDirectory inMemoryNoOpCommitDirectory = new InMemoryNoOpCommitDirectory(searchableSnapshotDirectory);
86+
Directory directory = new SearchableSnapshotDirectory(snapshot, blobContainer);
87+
if (SNAPSHOT_CACHE_ENABLED_SETTING.get(indexSettings.getSettings())) {
88+
final Path cacheDir = shardPath.getDataPath().resolve("snapshots").resolve(snapshotId.getUUID());
89+
directory = new CacheDirectory(directory, cacheService, cacheDir);
90+
}
91+
directory = new InMemoryNoOpCommitDirectory(directory);
8392

84-
try (IndexWriter indexWriter = new IndexWriter(inMemoryNoOpCommitDirectory, new IndexWriterConfig())) {
93+
try (IndexWriter indexWriter = new IndexWriter(directory, new IndexWriterConfig())) {
8594
final Map<String, String> userData = new HashMap<>();
8695
indexWriter.getLiveCommitData().forEach(e -> userData.put(e.getKey(), e.getValue()));
8796

@@ -94,7 +103,7 @@ private Directory makeDirectory(IndexSettings indexSettings, ShardPath shardPath
94103
indexWriter.commit();
95104
}
96105

97-
return inMemoryNoOpCommitDirectory;
106+
return directory;
98107
}
99108

100109
@Override
@@ -136,17 +145,21 @@ public Repository create(RepositoryMetaData metaData, Function<String, Factory>
136145
};
137146
}
138147

139-
public static IndexStorePlugin.DirectoryFactory newDirectoryFactory(final Supplier<RepositoriesService> repositoriesService) {
148+
public static IndexStorePlugin.DirectoryFactory newDirectoryFactory(final Supplier<RepositoriesService> repositoriesService,
149+
final Supplier<CacheService> cacheService) {
140150
return (indexSettings, shardPath) -> {
141151
final RepositoriesService repositories = repositoriesService.get();
142152
assert repositories != null;
143153

144154
final Repository repository = repositories.repository(SNAPSHOT_REPOSITORY_SETTING.get(indexSettings.getSettings()));
145155
if (repository instanceof SearchableSnapshotRepository == false) {
146-
throw new IllegalArgumentException("Repository [" + repository + "] is not searchable" );
156+
throw new IllegalArgumentException("Repository [" + repository + "] is not searchable");
147157
}
148158

149-
return ((SearchableSnapshotRepository)repository).makeDirectory(indexSettings, shardPath);
159+
final CacheService cache = cacheService.get();
160+
assert cache != null;
161+
162+
return ((SearchableSnapshotRepository) repository).makeDirectory(indexSettings, shardPath, cache);
150163
};
151164
}
152165
}

x-pack/plugin/searchable-snapshots/src/main/java/org/elasticsearch/xpack/searchablesnapshots/SearchableSnapshots.java

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,14 @@
66
package org.elasticsearch.xpack.searchablesnapshots;
77

88
import org.apache.lucene.util.SetOnce;
9+
import org.elasticsearch.client.Client;
910
import org.elasticsearch.cluster.service.ClusterService;
11+
import org.elasticsearch.common.io.stream.NamedWriteableRegistry;
1012
import org.elasticsearch.common.settings.Setting;
13+
import org.elasticsearch.common.settings.Settings;
1114
import org.elasticsearch.common.xcontent.NamedXContentRegistry;
1215
import org.elasticsearch.env.Environment;
16+
import org.elasticsearch.env.NodeEnvironment;
1317
import org.elasticsearch.index.IndexSettings;
1418
import org.elasticsearch.index.engine.EngineFactory;
1519
import org.elasticsearch.index.engine.ReadOnlyEngine;
@@ -21,7 +25,12 @@
2125
import org.elasticsearch.repositories.RepositoriesModule;
2226
import org.elasticsearch.repositories.RepositoriesService;
2327
import org.elasticsearch.repositories.Repository;
28+
import org.elasticsearch.script.ScriptService;
29+
import org.elasticsearch.threadpool.ThreadPool;
30+
import org.elasticsearch.watcher.ResourceWatcherService;
31+
import org.elasticsearch.xpack.searchablesnapshots.cache.CacheService;
2432

33+
import java.util.Collection;
2534
import java.util.Collections;
2635
import java.util.List;
2736
import java.util.Map;
@@ -36,17 +45,41 @@
3645
public class SearchableSnapshots extends Plugin implements IndexStorePlugin, RepositoryPlugin, EnginePlugin {
3746

3847
private final SetOnce<RepositoriesService> repositoriesService;
48+
private final SetOnce<CacheService> cacheService;
49+
private final Settings settings;
3950

40-
public SearchableSnapshots() {
51+
public SearchableSnapshots(final Settings settings) {
4152
this.repositoriesService = new SetOnce<>();
53+
this.cacheService = new SetOnce<>();
54+
this.settings = settings;
4255
}
4356

4457
@Override
4558
public List<Setting<?>> getSettings() {
4659
return List.of(SearchableSnapshotRepository.SNAPSHOT_REPOSITORY_SETTING,
4760
SearchableSnapshotRepository.SNAPSHOT_SNAPSHOT_NAME_SETTING,
4861
SearchableSnapshotRepository.SNAPSHOT_SNAPSHOT_ID_SETTING,
49-
SearchableSnapshotRepository.SNAPSHOT_INDEX_ID_SETTING);
62+
SearchableSnapshotRepository.SNAPSHOT_INDEX_ID_SETTING,
63+
SearchableSnapshotRepository.SNAPSHOT_CACHE_ENABLED_SETTING,
64+
CacheService.SNAPSHOT_CACHE_SIZE_SETTING
65+
);
66+
}
67+
68+
@Override
69+
public Collection<Object> createComponents(
70+
final Client client,
71+
final ClusterService clusterService,
72+
final ThreadPool threadPool,
73+
final ResourceWatcherService resourceWatcherService,
74+
final ScriptService scriptService,
75+
final NamedXContentRegistry xContentRegistry,
76+
final Environment environment,
77+
final NodeEnvironment nodeEnvironment,
78+
final NamedWriteableRegistry namedWriteableRegistry) {
79+
80+
final CacheService cacheService = new CacheService(settings);
81+
this.cacheService.set(cacheService);
82+
return List.of(cacheService);
5083
}
5184

5285
@Override
@@ -57,7 +90,7 @@ public void onRepositoriesModule(RepositoriesModule repositoriesModule) {
5790
@Override
5891
public Map<String, DirectoryFactory> getDirectoryFactories() {
5992
return Map.of(SearchableSnapshotRepository.SNAPSHOT_DIRECTORY_FACTORY_KEY,
60-
SearchableSnapshotRepository.newDirectoryFactory(repositoriesService::get));
93+
SearchableSnapshotRepository.newDirectoryFactory(repositoriesService::get, cacheService::get));
6194
}
6295

6396
@Override

0 commit comments

Comments
 (0)