Skip to content

Commit 6cd68ca

Browse files
committed
add tests
1 parent cba172b commit 6cd68ca

File tree

4 files changed

+460
-20
lines changed

4 files changed

+460
-20
lines changed

modules/repository-gcs/src/main/java/org/elasticsearch/repositories/gcs/GoogleCloudStorageClientsManager.java

Lines changed: 44 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,9 @@ public class GoogleCloudStorageClientsManager implements ClusterStateApplier {
4141
GcsRepositoryStatsCollector,
4242
MeteredStorage,
4343
IOException> clientBuilder;
44-
private final ClusterClientsHolder clusterClientsHolder = new ClusterClientsHolder();
45-
private final Map<ProjectId, ClientsHolder> projectClientHolders;
44+
// A map of projectId to clients holder. Adding to and removing from the map happen only in the applier thread.
45+
private final Map<ProjectId, ClientsHolder> perProjectClientsHolders;
46+
private final ClusterClientsHolder clusterClientsHolder;
4647

4748
public GoogleCloudStorageClientsManager(
4849
Settings nodeSettings,
@@ -55,15 +56,16 @@ public GoogleCloudStorageClientsManager(
5556
.build();
5657
this.clientBuilder = clientBuilder;
5758
if (supportsMultipleProjects) {
58-
this.projectClientHolders = ConcurrentCollections.newConcurrentMap();
59+
this.perProjectClientsHolders = ConcurrentCollections.newConcurrentMap();
5960
} else {
60-
this.projectClientHolders = null;
61+
this.perProjectClientsHolders = null;
6162
}
63+
this.clusterClientsHolder = new ClusterClientsHolder();
6264
}
6365

6466
@Override
6567
public void applyClusterState(ClusterChangedEvent event) {
66-
assert projectClientHolders != null;
68+
assert perProjectClientsHolders != null;
6769
final Map<ProjectId, ProjectMetadata> currentProjects = event.state().metadata().projects();
6870

6971
final var updatedPerProjectClients = new HashMap<ProjectId, ClientsHolder>();
@@ -77,7 +79,7 @@ public void applyClusterState(ClusterChangedEvent event) {
7779
// Project secrets can be null when node restarts. It may not have any s3 credentials if s3 is not in use.
7880
if (projectSecrets == null || projectSecrets.getSettingNames().stream().noneMatch(key -> key.startsWith(GCS_SETTING_PREFIX))) {
7981
// Most likely there won't be any existing client, but attempt to remove it anyway just in case
80-
projectClientHolders.remove(project.id());
82+
perProjectClientsHolders.remove(project.id());
8183
continue;
8284
}
8385

@@ -113,13 +115,13 @@ public void applyClusterState(ClusterChangedEvent event) {
113115
// Updated projects
114116
for (var projectId : updatedPerProjectClients.keySet()) {
115117
assert ProjectId.DEFAULT.equals(projectId) == false;
116-
projectClientHolders.put(projectId, updatedPerProjectClients.get(projectId));
118+
perProjectClientsHolders.put(projectId, updatedPerProjectClients.get(projectId));
117119
}
118120
// Removed projects
119-
for (var projectId : projectClientHolders.keySet()) {
121+
for (var projectId : perProjectClientsHolders.keySet()) {
120122
if (currentProjects.containsKey(projectId) == false) {
121123
assert ProjectId.DEFAULT.equals(projectId) == false;
122-
projectClientHolders.remove(projectId);
124+
perProjectClientsHolders.remove(projectId);
123125
}
124126
}
125127
}
@@ -140,23 +142,41 @@ void refreshAndClearCacheForClusterClients(Map<String, GoogleCloudStorageClientS
140142

141143
MeteredStorage client(ProjectId projectId, String clientName, String repositoryName, GcsRepositoryStatsCollector statsCollector)
142144
throws IOException {
143-
return getClientsHolderSafe(projectId).client(clientName, repositoryName, statsCollector);
145+
if (projectId == null || ProjectId.DEFAULT.equals(projectId)) {
146+
return clusterClientsHolder.client(clientName, repositoryName, statsCollector);
147+
} else {
148+
return getClientsHolderSafe(projectId).client(clientName, repositoryName, statsCollector);
149+
}
144150
}
145151

146152
void closeRepositoryClients(ProjectId projectId, String repositoryName) {
147-
getClientsHolderSafe(projectId).closeRepositoryClients(repositoryName);
153+
if (projectId == null || ProjectId.DEFAULT.equals(projectId)) {
154+
clusterClientsHolder.closeRepositoryClients(repositoryName);
155+
} else {
156+
getClientsHolderSafe(projectId).closeRepositoryClients(repositoryName);
157+
}
158+
}
159+
160+
// package private for tests
161+
ClusterClientsHolder getClusterClientsHolder() {
162+
return clusterClientsHolder;
163+
}
164+
165+
// package private for tests
166+
Map<ProjectId, ClientsHolder> getPerProjectClientsHolders() {
167+
return perProjectClientsHolders == null ? null : Map.copyOf(perProjectClientsHolders);
148168
}
149169

150170
private boolean newOrUpdated(ProjectId projectId, Map<String, GoogleCloudStorageClientSettings> currentClientSettings) {
151-
final var old = projectClientHolders.get(projectId);
171+
final var old = perProjectClientsHolders.get(projectId);
152172
if (old == null) {
153173
return true;
154174
}
155-
return currentClientSettings.equals(old.getClientSettings()) == false;
175+
return currentClientSettings.equals(old.allClientSettings()) == false;
156176
}
157177

158178
private ClientsHolder getClientsHolderSafe(ProjectId projectId) {
159-
final var clientsHolder = projectClientHolders.get(projectId);
179+
final var clientsHolder = perProjectClientsHolders.get(projectId);
160180
if (clientsHolder == null) {
161181
assert ProjectId.DEFAULT.equals(projectId) == false;
162182
throw new IllegalArgumentException("No GCS client is configured for project [" + projectId + "]");
@@ -175,7 +195,7 @@ abstract class ClientsHolder {
175195
/**
176196
* Get the current client settings for all clients in this holder.
177197
*/
178-
protected abstract Map<String, GoogleCloudStorageClientSettings> getClientSettings();
198+
protected abstract Map<String, GoogleCloudStorageClientSettings> allClientSettings();
179199

180200
/**
181201
* Attempts to retrieve a client from the cache. If the client does not exist it
@@ -204,14 +224,14 @@ MeteredStorage client(final String clientName, final String repositoryName, fina
204224
return existing;
205225
}
206226

207-
final GoogleCloudStorageClientSettings settings = getClientSettings().get(clientName);
227+
final GoogleCloudStorageClientSettings settings = allClientSettings().get(clientName);
208228

209229
if (settings == null) {
210230
throw new IllegalArgumentException(
211231
"Unknown client name ["
212232
+ clientName
213233
+ "]. Existing client configs: "
214-
+ Strings.collectionToDelimitedString(getClientSettings().keySet(), ",")
234+
+ Strings.collectionToDelimitedString(allClientSettings().keySet(), ",")
215235
);
216236
}
217237

@@ -228,14 +248,19 @@ synchronized void closeRepositoryClients(String repositoryName) {
228248
.filter(entry -> entry.getKey().equals(repositoryName) == false)
229249
.collect(Collectors.toUnmodifiableMap(Map.Entry::getKey, java.util.Map.Entry::getValue));
230250
}
251+
252+
// package private for tests
253+
final boolean hasCachedClientForRepository(String repositoryName) {
254+
return clientCache.containsKey(repositoryName);
255+
}
231256
}
232257

233258
final class ClusterClientsHolder extends ClientsHolder {
234259

235260
private volatile Map<String, GoogleCloudStorageClientSettings> clientSettings = emptyMap();
236261

237262
@Override
238-
protected Map<String, GoogleCloudStorageClientSettings> getClientSettings() {
263+
protected Map<String, GoogleCloudStorageClientSettings> allClientSettings() {
239264
return clientSettings;
240265
}
241266

@@ -261,7 +286,7 @@ final class PerProjectClientsHolder extends ClientsHolder {
261286
}
262287

263288
@Override
264-
protected Map<String, GoogleCloudStorageClientSettings> getClientSettings() {
289+
protected Map<String, GoogleCloudStorageClientSettings> allClientSettings() {
265290
return clientSettings;
266291
}
267292
}

modules/repository-gcs/src/main/java/org/elasticsearch/repositories/gcs/GoogleCloudStorageService.java

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import org.apache.logging.log4j.LogManager;
2626
import org.apache.logging.log4j.Logger;
2727
import org.elasticsearch.ExceptionsHelper;
28+
import org.elasticsearch.cluster.metadata.ProjectId;
2829
import org.elasticsearch.cluster.node.DiscoveryNode;
2930
import org.elasticsearch.cluster.project.ProjectResolver;
3031
import org.elasticsearch.cluster.service.ClusterService;
@@ -97,15 +98,47 @@ public void refreshAndClearCache(Map<String, GoogleCloudStorageClientSettings> c
9798
* @return a cached client storage instance that can be used to manage objects
9899
* (blobs)
99100
*/
101+
@Deprecated(forRemoval = true)
100102
public MeteredStorage client(final String clientName, final String repositoryName, final GcsRepositoryStatsCollector statsCollector)
101103
throws IOException {
102104
return clientsManager.client(clientName, repositoryName, statsCollector);
103105
}
104106

107+
/**
108+
* Attempts to retrieve a client from the cache. If the client does not exist it
109+
* will be created from the latest settings and will populate the cache. The
110+
* returned instance should not be cached by the calling code. Instead, for each
111+
* use, the (possibly updated) instance should be requested by calling this
112+
* method.
113+
*
114+
* @param clientName name of the client settings used to create the client
115+
* @param repositoryName name of the repository that would use the client
116+
* @return a cached client storage instance that can be used to manage objects
117+
* (blobs)
118+
*/
119+
public MeteredStorage client(
120+
final ProjectId projectId,
121+
final String clientName,
122+
final String repositoryName,
123+
final GcsRepositoryStatsCollector statsCollector
124+
) throws IOException {
125+
return clientsManager.client(projectId, clientName, repositoryName, statsCollector);
126+
}
127+
128+
@Deprecated(forRemoval = true)
105129
void closeRepositoryClients(String repositoryName) {
106130
clientsManager.closeRepositoryClients(repositoryName);
107131
}
108132

133+
void closeRepositoryClients(final ProjectId projectId, String repositoryName) {
134+
clientsManager.closeRepositoryClients(projectId, repositoryName);
135+
}
136+
137+
// package-private for tests
138+
GoogleCloudStorageClientsManager getClientsManager() {
139+
return clientsManager;
140+
}
141+
109142
/**
110143
* Creates a client that can be used to manage Google Cloud Storage objects. The client is thread-safe.
111144
*

0 commit comments

Comments
 (0)