4
4
* you may not use this file except in compliance with the Elastic License.
5
5
*/
6
6
7
- package org .elasticsearch .xpack .searchablesnapshots ;
7
+ package org .elasticsearch .xpack .searchablesnapshots . cache ;
8
8
9
- import org .apache .lucene .mockfile .FilterFileSystemProvider ;
10
- import org .elasticsearch .action .admin .cluster .snapshots .restore .RestoreSnapshotResponse ;
9
+ import org .apache .lucene .document .Document ;
11
10
import org .elasticsearch .cluster .metadata .IndexMetadata ;
12
11
import org .elasticsearch .cluster .node .DiscoveryNode ;
13
12
import 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 ;
17
13
import org .elasticsearch .common .settings .Settings ;
18
14
import org .elasticsearch .common .unit .ByteSizeUnit ;
19
15
import org .elasticsearch .common .unit .ByteSizeValue ;
20
16
import org .elasticsearch .index .Index ;
21
17
import org .elasticsearch .index .IndexService ;
18
+ import org .elasticsearch .index .shard .ShardPath ;
22
19
import org .elasticsearch .indices .IndicesService ;
23
20
import org .elasticsearch .snapshots .SnapshotInfo ;
24
21
import 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 ;
30
23
31
24
import java .io .IOException ;
32
25
import java .nio .file .DirectoryStream ;
33
- import java .nio .file .FileSystem ;
34
26
import java .nio .file .Files ;
35
27
import java .nio .file .Path ;
36
28
import java .util .HashSet ;
37
29
import java .util .Locale ;
30
+ import java .util .Map ;
38
31
import java .util .Set ;
39
- import java .util .concurrent .atomic .AtomicBoolean ;
40
32
41
33
import static org .elasticsearch .cluster .metadata .IndexMetadata .INDEX_ROUTING_REQUIRE_GROUP_PREFIX ;
42
34
import static org .elasticsearch .index .IndexSettings .INDEX_SOFT_DELETES_SETTING ;
43
35
import static org .elasticsearch .test .hamcrest .ElasticsearchAssertions .assertAcked ;
36
+ import static org .elasticsearch .xpack .searchablesnapshots .cache .PersistentCache .resolveCacheIndexFolder ;
44
37
import static org .hamcrest .Matchers .equalTo ;
45
38
import static org .hamcrest .Matchers .greaterThan ;
39
+ import static org .hamcrest .Matchers .notNullValue ;
46
40
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 {
89
42
90
43
@ Override
91
44
protected Settings nodeSettings (int nodeOrdinal ) {
@@ -96,7 +49,7 @@ protected Settings nodeSettings(int nodeOrdinal) {
96
49
.build ();
97
50
}
98
51
99
- public void testCacheDirectoriesRemovedOnStartup () throws Exception {
52
+ public void testCacheSurviveRestart () throws Exception {
100
53
final String fsRepoName = randomAlphaOfLength (10 );
101
54
final String indexName = randomAlphaOfLength (10 ).toLowerCase (Locale .ROOT );
102
55
final String restoredIndexName = randomBoolean () ? indexName : randomAlphaOfLength (10 ).toLowerCase (Locale .ROOT );
@@ -117,18 +70,13 @@ public void testCacheDirectoriesRemovedOnStartup() throws Exception {
117
70
final DiscoveryNodes discoveryNodes = client ().admin ().cluster ().prepareState ().clear ().setNodes (true ).get ().getState ().nodes ();
118
71
final String dataNode = randomFrom (discoveryNodes .getDataNodes ().values ().toArray (DiscoveryNode .class )).getName ();
119
72
120
- final MountSearchableSnapshotRequest req = new MountSearchableSnapshotRequest (
121
- restoredIndexName ,
73
+ mountSnapshot (
122
74
fsRepoName ,
123
75
snapshotName ,
124
76
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 ()
128
79
);
129
-
130
- final RestoreSnapshotResponse restoreSnapshotResponse = client ().execute (MountSearchableSnapshotAction .INSTANCE , req ).get ();
131
- assertThat (restoreSnapshotResponse .getRestoreInfo ().failedShards (), equalTo (0 ));
132
80
ensureGreen (restoredIndexName );
133
81
134
82
final Index restoredIndex = client ().admin ()
@@ -143,7 +91,9 @@ public void testCacheDirectoriesRemovedOnStartup() throws Exception {
143
91
.getIndex ();
144
92
145
93
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
+
147
97
assertTrue (Files .isDirectory (shardCachePath ));
148
98
final Set <Path > cacheFiles = new HashSet <>();
149
99
try (DirectoryStream <Path > snapshotCacheStream = Files .newDirectoryStream (shardCachePath )) {
@@ -159,25 +109,49 @@ public void testCacheDirectoriesRemovedOnStartup() throws Exception {
159
109
}
160
110
assertFalse ("no cache files found" , cacheFiles .isEmpty ());
161
111
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
+
163
118
internalCluster ().restartNode (dataNode , new InternalTestCluster .RestartCallback () {
164
119
@ Override
165
120
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 );
169
137
}
170
- stopBlockingDeletes ();
171
138
return Settings .EMPTY ;
172
139
}
173
140
});
174
141
142
+ persistentCache = internalCluster ().getInstance (CacheService .class , dataNode ).getPersistentCache ();
143
+ assertThat (persistentCache .getNumDocs (), equalTo ((long ) cacheFiles .size ()));
175
144
ensureGreen (restoredIndexName );
176
145
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 )));
180
147
181
148
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 ));
182
156
}
183
157
}
0 commit comments