44 * you may not use this file except in compliance with the Elastic License.
55 */
66
7- package org .elasticsearch .xpack .searchablesnapshots ;
7+ package org .elasticsearch .xpack .searchablesnapshots . cache ;
88
9- import org .apache .lucene .mockfile .FilterFileSystemProvider ;
10- import org .elasticsearch .action .admin .cluster .snapshots .restore .RestoreSnapshotResponse ;
9+ import org .apache .lucene .document .Document ;
1110import org .elasticsearch .cluster .metadata .IndexMetadata ;
1211import org .elasticsearch .cluster .node .DiscoveryNode ;
1312import org .elasticsearch .cluster .node .DiscoveryNodes ;
14- import org .elasticsearch .common .Strings ;
15- import org .elasticsearch .common .io .PathUtils ;
16- import org .elasticsearch .common .io .PathUtilsForTesting ;
1713import org .elasticsearch .common .settings .Settings ;
1814import org .elasticsearch .common .unit .ByteSizeUnit ;
1915import org .elasticsearch .common .unit .ByteSizeValue ;
2016import org .elasticsearch .index .Index ;
2117import org .elasticsearch .index .IndexService ;
18+ import org .elasticsearch .index .shard .ShardPath ;
2219import org .elasticsearch .indices .IndicesService ;
2320import org .elasticsearch .snapshots .SnapshotInfo ;
2421import org .elasticsearch .test .InternalTestCluster ;
25- import org .elasticsearch .xpack .core .searchablesnapshots .MountSearchableSnapshotAction ;
26- import org .elasticsearch .xpack .core .searchablesnapshots .MountSearchableSnapshotRequest ;
27- import org .elasticsearch .xpack .searchablesnapshots .cache .CacheService ;
28- import org .junit .AfterClass ;
29- import org .junit .BeforeClass ;
22+ import org .elasticsearch .xpack .searchablesnapshots .BaseSearchableSnapshotsIntegTestCase ;
3023
3124import java .io .IOException ;
3225import java .nio .file .DirectoryStream ;
33- import java .nio .file .FileSystem ;
3426import java .nio .file .Files ;
3527import java .nio .file .Path ;
3628import java .util .HashSet ;
3729import java .util .Locale ;
30+ import java .util .Map ;
3831import java .util .Set ;
39- import java .util .concurrent .atomic .AtomicBoolean ;
4032
4133import static org .elasticsearch .cluster .metadata .IndexMetadata .INDEX_ROUTING_REQUIRE_GROUP_PREFIX ;
4234import static org .elasticsearch .index .IndexSettings .INDEX_SOFT_DELETES_SETTING ;
4335import static org .elasticsearch .test .hamcrest .ElasticsearchAssertions .assertAcked ;
36+ import static org .elasticsearch .xpack .searchablesnapshots .cache .PersistentCache .resolveCacheIndexFolder ;
4437import static org .hamcrest .Matchers .equalTo ;
4538import static org .hamcrest .Matchers .greaterThan ;
39+ import static org .hamcrest .Matchers .notNullValue ;
4640
47- public class SearchableSnapshotsCacheClearingIntegTests extends BaseSearchableSnapshotsIntegTestCase {
48-
49- private static DeleteBlockingFileSystemProvider deleteBlockingFileSystemProvider ;
50-
51- @ BeforeClass
52- public static void installDeleteBlockingFileSystemProvider () {
53- FileSystem current = PathUtils .getDefaultFileSystem ();
54- deleteBlockingFileSystemProvider = new DeleteBlockingFileSystemProvider (current );
55- PathUtilsForTesting .installMock (deleteBlockingFileSystemProvider .getFileSystem (null ));
56- }
57-
58- @ AfterClass
59- public static void removeDeleteBlockingFileSystemProvider () {
60- PathUtilsForTesting .teardown ();
61- }
62-
63- void startBlockingDeletes () {
64- deleteBlockingFileSystemProvider .injectFailures .set (true );
65- }
66-
67- void stopBlockingDeletes () {
68- deleteBlockingFileSystemProvider .injectFailures .set (false );
69- }
70-
71- private static class DeleteBlockingFileSystemProvider extends FilterFileSystemProvider {
72-
73- AtomicBoolean injectFailures = new AtomicBoolean ();
74-
75- DeleteBlockingFileSystemProvider (FileSystem inner ) {
76- super ("deleteblocking://" , inner );
77- }
78-
79- @ Override
80- public boolean deleteIfExists (Path path ) throws IOException {
81- if (injectFailures .get ()) {
82- throw new IOException ("blocked deletion of " + path );
83- } else {
84- return super .deleteIfExists (path );
85- }
86- }
87-
88- }
41+ public class SearchableSnapshotsPersistentCacheIntegTests extends BaseSearchableSnapshotsIntegTestCase {
8942
9043 @ Override
9144 protected Settings nodeSettings (int nodeOrdinal ) {
@@ -96,7 +49,7 @@ protected Settings nodeSettings(int nodeOrdinal) {
9649 .build ();
9750 }
9851
99- public void testCacheDirectoriesRemovedOnStartup () throws Exception {
52+ public void testCacheSurviveRestart () throws Exception {
10053 final String fsRepoName = randomAlphaOfLength (10 );
10154 final String indexName = randomAlphaOfLength (10 ).toLowerCase (Locale .ROOT );
10255 final String restoredIndexName = randomBoolean () ? indexName : randomAlphaOfLength (10 ).toLowerCase (Locale .ROOT );
@@ -117,18 +70,13 @@ public void testCacheDirectoriesRemovedOnStartup() throws Exception {
11770 final DiscoveryNodes discoveryNodes = client ().admin ().cluster ().prepareState ().clear ().setNodes (true ).get ().getState ().nodes ();
11871 final String dataNode = randomFrom (discoveryNodes .getDataNodes ().values ().toArray (DiscoveryNode .class )).getName ();
11972
120- final MountSearchableSnapshotRequest req = new MountSearchableSnapshotRequest (
121- restoredIndexName ,
73+ mountSnapshot (
12274 fsRepoName ,
12375 snapshotName ,
12476 indexName ,
125- Settings .builder ().put (INDEX_ROUTING_REQUIRE_GROUP_PREFIX + "._name" , dataNode ).build (),
126- Strings .EMPTY_ARRAY ,
127- true
77+ restoredIndexName ,
78+ Settings .builder ().put (INDEX_ROUTING_REQUIRE_GROUP_PREFIX + "._name" , dataNode ).build ()
12879 );
129-
130- final RestoreSnapshotResponse restoreSnapshotResponse = client ().execute (MountSearchableSnapshotAction .INSTANCE , req ).get ();
131- assertThat (restoreSnapshotResponse .getRestoreInfo ().failedShards (), equalTo (0 ));
13280 ensureGreen (restoredIndexName );
13381
13482 final Index restoredIndex = client ().admin ()
@@ -143,7 +91,9 @@ public void testCacheDirectoriesRemovedOnStartup() throws Exception {
14391 .getIndex ();
14492
14593 final IndexService indexService = internalCluster ().getInstance (IndicesService .class , dataNode ).indexService (restoredIndex );
146- final Path shardCachePath = CacheService .getShardCachePath (indexService .getShard (0 ).shardPath ());
94+ final ShardPath shardPath = indexService .getShard (0 ).shardPath ();
95+ final Path shardCachePath = CacheService .getShardCachePath (shardPath );
96+
14797 assertTrue (Files .isDirectory (shardCachePath ));
14898 final Set <Path > cacheFiles = new HashSet <>();
14999 try (DirectoryStream <Path > snapshotCacheStream = Files .newDirectoryStream (shardCachePath )) {
@@ -159,25 +109,49 @@ public void testCacheDirectoriesRemovedOnStartup() throws Exception {
159109 }
160110 assertFalse ("no cache files found" , cacheFiles .isEmpty ());
161111
162- startBlockingDeletes ();
112+ CacheService cacheService = internalCluster ().getInstance (CacheService .class , dataNode );
113+ cacheService .synchronizeCache ();
114+
115+ PersistentCache persistentCache = cacheService .getPersistentCache ();
116+ assertThat (persistentCache .getNumDocs (), equalTo ((long ) cacheFiles .size ()));
117+
163118 internalCluster ().restartNode (dataNode , new InternalTestCluster .RestartCallback () {
164119 @ Override
165120 public Settings onNodeStopped (String nodeName ) {
166- assertTrue (Files .isDirectory (shardCachePath ));
167- for (Path cacheFile : cacheFiles ) {
168- assertTrue (cacheFile + " should not have been cleaned up yet" , Files .isRegularFile (cacheFile ));
121+ try {
122+ assertTrue (Files .isDirectory (shardCachePath ));
123+
124+ final Path persistentCacheIndexDir = resolveCacheIndexFolder (shardPath .getRootDataPath ());
125+ assertTrue (Files .isDirectory (persistentCacheIndexDir ));
126+
127+ final Map <String , Document > documents = PersistentCache .loadDocuments (persistentCacheIndexDir );
128+ assertThat (documents .size (), equalTo (cacheFiles .size ()));
129+
130+ for (Path cacheFile : cacheFiles ) {
131+ final String cacheFileName = cacheFile .getFileName ().toString ();
132+ assertTrue (cacheFileName + " should exist on disk" , Files .isRegularFile (cacheFile ));
133+ assertThat (cacheFileName + " should exist in persistent cache index" , documents .get (cacheFileName ), notNullValue ());
134+ }
135+ } catch (IOException e ) {
136+ throw new AssertionError (e );
169137 }
170- stopBlockingDeletes ();
171138 return Settings .EMPTY ;
172139 }
173140 });
174141
142+ persistentCache = internalCluster ().getInstance (CacheService .class , dataNode ).getPersistentCache ();
143+ assertThat (persistentCache .getNumDocs (), equalTo ((long ) cacheFiles .size ()));
175144 ensureGreen (restoredIndexName );
176145
177- for (Path cacheFile : cacheFiles ) {
178- assertFalse (cacheFile + " should have been cleaned up" , Files .exists (cacheFile ));
179- }
146+ cacheFiles .forEach (cacheFile -> assertTrue (cacheFile + " should have survived node restart" , Files .exists (cacheFile )));
180147
181148 assertAcked (client ().admin ().indices ().prepareDelete (restoredIndexName ));
149+
150+ assertBusy (() -> cacheFiles .forEach (cacheFile -> assertFalse (cacheFile + " should have been cleaned up" , Files .exists (cacheFile ))));
151+ cacheService = internalCluster ().getInstance (CacheService .class , dataNode );
152+ cacheService .synchronizeCache ();
153+
154+ persistentCache = cacheService .getPersistentCache ();
155+ assertThat (persistentCache .getNumDocs (), equalTo (0L ));
182156 }
183157}
0 commit comments