Add REST API to list indexes and their versions
This change is a preparation to implement a REST API endpoint to
take snapshots of indexes.
Release-Notes: REST API to list indexes and their versions
Change-Id: Ib1e354a8abe5149826d94bca9aaecfea99a2e6ff
diff --git a/Documentation/rest-api-config.txt b/Documentation/rest-api-config.txt
index ec1ac03..70c4b4d 100644
--- a/Documentation/rest-api-config.txt
+++ b/Documentation/rest-api-config.txt
@@ -1420,6 +1420,73 @@
When `delete_missing` is set to `true` changes to be reindexed which are missing in NoteDb
will be deleted in the index.
+[[list-indexes]]
+=== List Indexes
+--
+'GET /config/server/indexes'
+--
+
+Lists the indexes used by Gerrit. It provides details about the index versions,
+which index version is used to search and which versions are written to.
+
+This endpoint requires the
+link:access-control.html#capability_maintainServer[Maintain Server]
+capability.
+
+.Request
+----
+ GET /config/server/indexes/ HTTP/1.0
+----
+
+.Response
+----
+ HTTP/1.1 200 OK
+ Content-Type: application/json; charset=UTF-8
+
+ )]}'
+ {
+ "accounts": {
+ "name": "accounts",
+ "versions": {
+ "13": {
+ "write": true,
+ "search": true
+ }
+ }
+ },
+ "changes": {
+ "name": "changes",
+ "versions": {
+ "83": {
+ "write": true,
+ "search": true
+ },
+ "84": {
+ "write": true,
+ "search": false
+ }
+ }
+ },
+ "groups": {
+ "name": "groups",
+ "versions": {
+ "10": {
+ "write": true,
+ "search": true
+ }
+ }
+ },
+ "projects": {
+ "name": "projects",
+ "versions": {
+ "8": {
+ "write": true,
+ "search": true
+ }
+ }
+ }
+ }
+----
[[ids]]
== IDs
diff --git a/java/com/google/gerrit/server/config/IndexResource.java b/java/com/google/gerrit/server/config/IndexResource.java
new file mode 100644
index 0000000..ea1b57a
--- /dev/null
+++ b/java/com/google/gerrit/server/config/IndexResource.java
@@ -0,0 +1,36 @@
+// Copyright (C) 2023 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.server.config;
+
+import com.google.gerrit.extensions.restapi.RestView;
+import com.google.gerrit.index.Index;
+import com.google.gerrit.index.IndexCollection;
+import com.google.inject.TypeLiteral;
+import java.util.Collection;
+
+public class IndexResource extends ConfigResource {
+ public static final TypeLiteral<RestView<IndexResource>> INDEX_KIND = new TypeLiteral<>() {};
+
+ private final IndexCollection<?, ?, ?> indexes;
+
+ public IndexResource(IndexCollection<?, ?, ?> indexes) {
+ this.indexes = indexes;
+ }
+
+ @SuppressWarnings("unchecked")
+ public Collection<Index<?, ?>> getWriteIndexes() {
+ return (Collection<Index<?, ?>>) indexes.getWriteIndexes();
+ }
+}
diff --git a/java/com/google/gerrit/server/restapi/config/ConfigRestApiModule.java b/java/com/google/gerrit/server/restapi/config/ConfigRestApiModule.java
index 3de05e9..f34a4a3 100644
--- a/java/com/google/gerrit/server/restapi/config/ConfigRestApiModule.java
+++ b/java/com/google/gerrit/server/restapi/config/ConfigRestApiModule.java
@@ -15,6 +15,7 @@
package com.google.gerrit.server.restapi.config;
import static com.google.gerrit.server.config.ConfigResource.CONFIG_KIND;
+import static com.google.gerrit.server.config.IndexResource.INDEX_KIND;
import static com.google.gerrit.server.config.TaskResource.TASK_KIND;
import com.google.gerrit.extensions.registration.DynamicMap;
@@ -29,6 +30,7 @@
DynamicMap.mapOf(binder(), CONFIG_KIND);
DynamicMap.mapOf(binder(), TASK_KIND);
DynamicMap.mapOf(binder(), TopMenuResource.TOP_MENU_KIND);
+ DynamicMap.mapOf(binder(), INDEX_KIND);
child(CONFIG_KIND, "capabilities").to(CapabilitiesCollection.class);
post(CONFIG_KIND, "check.consistency").to(CheckConsistency.class);
@@ -50,6 +52,7 @@
child(CONFIG_KIND, "top-menus").to(TopMenuCollection.class);
get(CONFIG_KIND, "version").to(GetVersion.class);
+ child(CONFIG_KIND, "indexes").to(IndexCollection.class);
// The caches and summary REST endpoints are bound via RestCacheAdminModule.
}
}
diff --git a/java/com/google/gerrit/server/restapi/config/IndexCollection.java b/java/com/google/gerrit/server/restapi/config/IndexCollection.java
new file mode 100644
index 0000000..3e00ebd
--- /dev/null
+++ b/java/com/google/gerrit/server/restapi/config/IndexCollection.java
@@ -0,0 +1,72 @@
+// Copyright (C) 2023 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.server.restapi.config;
+
+import static com.google.gerrit.common.data.GlobalCapability.MAINTAIN_SERVER;
+
+import com.google.gerrit.extensions.annotations.RequiresCapability;
+import com.google.gerrit.extensions.registration.DynamicMap;
+import com.google.gerrit.extensions.restapi.ChildCollection;
+import com.google.gerrit.extensions.restapi.IdString;
+import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
+import com.google.gerrit.extensions.restapi.RestApiException;
+import com.google.gerrit.extensions.restapi.RestView;
+import com.google.gerrit.index.IndexDefinition;
+import com.google.gerrit.server.config.ConfigResource;
+import com.google.gerrit.server.config.IndexResource;
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+import com.google.inject.Singleton;
+import java.util.Collection;
+
+@RequiresCapability(MAINTAIN_SERVER)
+@Singleton
+public class IndexCollection implements ChildCollection<ConfigResource, IndexResource> {
+ private final DynamicMap<RestView<IndexResource>> views;
+ private final Provider<ListIndexes> list;
+ private final Collection<IndexDefinition<?, ?, ?>> defs;
+
+ @Inject
+ IndexCollection(
+ DynamicMap<RestView<IndexResource>> views,
+ Provider<ListIndexes> list,
+ Collection<IndexDefinition<?, ?, ?>> defs) {
+ this.views = views;
+ this.list = list;
+ this.defs = defs;
+ }
+
+ @Override
+ public IndexResource parse(ConfigResource parent, IdString id) throws ResourceNotFoundException {
+ String indexName = id.get();
+
+ for (IndexDefinition<?, ?, ?> def : defs) {
+ if (def.getName().equals(indexName)) {
+ return new IndexResource(def.getIndexCollection());
+ }
+ }
+ throw new ResourceNotFoundException("Unknown index requested: " + indexName);
+ }
+
+ @Override
+ public RestView<ConfigResource> list() throws RestApiException {
+ return list.get();
+ }
+
+ @Override
+ public DynamicMap<RestView<IndexResource>> views() {
+ return views;
+ }
+}
diff --git a/java/com/google/gerrit/server/restapi/config/IndexInfo.java b/java/com/google/gerrit/server/restapi/config/IndexInfo.java
new file mode 100644
index 0000000..4a6bd3e53
--- /dev/null
+++ b/java/com/google/gerrit/server/restapi/config/IndexInfo.java
@@ -0,0 +1,58 @@
+// Copyright (C) 2023 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.server.restapi.config;
+
+import com.google.auto.value.AutoValue;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSortedMap;
+import com.google.gerrit.index.Index;
+import com.google.gerrit.index.IndexCollection;
+
+@AutoValue
+public abstract class IndexInfo {
+
+ public static IndexInfo fromIndexCollection(
+ String name, IndexCollection<?, ?, ?> indexCollection) {
+ ImmutableSortedMap.Builder<Integer, IndexVersionInfo> versions =
+ ImmutableSortedMap.naturalOrder();
+ int searchIndexVersion = indexCollection.getSearchIndex().getSchema().getVersion();
+ boolean searchIndexAdded = false;
+ for (Index<?, ?> index : indexCollection.getWriteIndexes()) {
+ boolean isSearchIndex = index.getSchema().getVersion() == searchIndexVersion;
+ versions.put(index.getSchema().getVersion(), IndexVersionInfo.create(true, isSearchIndex));
+ searchIndexAdded = searchIndexAdded || isSearchIndex;
+ }
+ if (!searchIndexAdded) {
+ versions.put(searchIndexVersion, IndexVersionInfo.create(false, true));
+ }
+
+ return new AutoValue_IndexInfo(name, versions.build());
+ }
+
+ public abstract String getName();
+
+ public abstract ImmutableMap<Integer, IndexVersionInfo> getVersions();
+
+ @AutoValue
+ public abstract static class IndexVersionInfo {
+ static IndexVersionInfo create(boolean write, boolean search) {
+ return new AutoValue_IndexInfo_IndexVersionInfo(write, search);
+ }
+
+ abstract boolean isWrite();
+
+ abstract boolean isSearch();
+ }
+}
diff --git a/java/com/google/gerrit/server/restapi/config/ListIndexes.java b/java/com/google/gerrit/server/restapi/config/ListIndexes.java
new file mode 100644
index 0000000..9710000
--- /dev/null
+++ b/java/com/google/gerrit/server/restapi/config/ListIndexes.java
@@ -0,0 +1,51 @@
+// Copyright (C) 2014 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.server.restapi.config;
+
+import static com.google.gerrit.common.data.GlobalCapability.MAINTAIN_SERVER;
+
+import com.google.gerrit.extensions.annotations.RequiresCapability;
+import com.google.gerrit.extensions.restapi.Response;
+import com.google.gerrit.extensions.restapi.RestReadView;
+import com.google.gerrit.index.IndexDefinition;
+import com.google.gerrit.server.config.ConfigResource;
+import com.google.inject.Inject;
+import java.util.Collection;
+import java.util.Map;
+import java.util.TreeMap;
+
+@RequiresCapability(MAINTAIN_SERVER)
+public class ListIndexes implements RestReadView<ConfigResource> {
+ private final Collection<IndexDefinition<?, ?, ?>> defs;
+
+ @Inject
+ public ListIndexes(Collection<IndexDefinition<?, ?, ?>> defs) {
+ this.defs = defs;
+ }
+
+ private Map<String, IndexInfo> getIndexInfos() {
+ Map<String, IndexInfo> indexInfos = new TreeMap<>();
+ for (IndexDefinition<?, ?, ?> def : defs) {
+ String name = def.getName();
+ indexInfos.put(name, IndexInfo.fromIndexCollection(name, def.getIndexCollection()));
+ }
+ return indexInfos;
+ }
+
+ @Override
+ public Response<Object> apply(ConfigResource rsrc) {
+ return Response.ok(getIndexInfos());
+ }
+}