Skip to content

Commit 53d3ce9

Browse files
olim7temerkle826
authored andcommitted
Add operation to get active compactions (fixes #364) (#365)
1 parent 759af48 commit 53d3ce9

File tree

4 files changed

+298
-0
lines changed

4 files changed

+298
-0
lines changed

management-api-agent-common/src/main/java/com/datastax/mgmtapi/NodeOpsProvider.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -381,6 +381,12 @@ public String forceKeyspaceCompaction(
381381
return submitJob(OperationType.COMPACTION.name(), compactionOperation, async);
382382
}
383383

384+
@Rpc(name = "getCompactions")
385+
public List<Map<String, String>> getCompactions() {
386+
logger.debug("Getting active compactions");
387+
return ShimLoader.instance.get().getCompactionManager().getCompactions();
388+
}
389+
384390
@Rpc(name = "garbageCollect")
385391
public void garbageCollect(
386392
@RpcParam(name = "tombstoneOption") String tombstoneOption,

management-api-server/doc/openapi.json

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1657,6 +1657,27 @@
16571657
"summary" : "Force a (major) compaction on one or more tables or user-defined compaction on given SSTables"
16581658
}
16591659
},
1660+
"/api/v1/ops/tables/compactions" : {
1661+
"get" : {
1662+
"operationId" : "getCompactions",
1663+
"responses" : {
1664+
"200" : {
1665+
"content" : {
1666+
"application/json" : {
1667+
"schema" : {
1668+
"type" : "array",
1669+
"items" : {
1670+
"$ref" : "#/components/schemas/Compaction"
1671+
}
1672+
}
1673+
}
1674+
},
1675+
"description" : "Compactions"
1676+
}
1677+
},
1678+
"summary" : "Returns active compactions"
1679+
}
1680+
},
16601681
"/api/v1/ops/tables/scrub" : {
16611682
"post" : {
16621683
"operationId" : "scrub_1",
@@ -1780,6 +1801,52 @@
17801801
},
17811802
"required" : [ "keyspace_name", "split_output", "user_defined" ]
17821803
},
1804+
"Compaction" : {
1805+
"type" : "object",
1806+
"properties" : {
1807+
"columnfamily" : {
1808+
"type" : "string"
1809+
},
1810+
"compactionId" : {
1811+
"type" : "string"
1812+
},
1813+
"completed" : {
1814+
"type" : "integer",
1815+
"format" : "int64"
1816+
},
1817+
"description" : {
1818+
"type" : "string"
1819+
},
1820+
"id" : {
1821+
"type" : "string"
1822+
},
1823+
"keyspace" : {
1824+
"type" : "string"
1825+
},
1826+
"operationId" : {
1827+
"type" : "string"
1828+
},
1829+
"operationType" : {
1830+
"type" : "string"
1831+
},
1832+
"sstables" : {
1833+
"type" : "string"
1834+
},
1835+
"targetDirectory" : {
1836+
"type" : "string"
1837+
},
1838+
"taskType" : {
1839+
"type" : "string"
1840+
},
1841+
"total" : {
1842+
"type" : "integer",
1843+
"format" : "int64"
1844+
},
1845+
"unit" : {
1846+
"type" : "string"
1847+
}
1848+
}
1849+
},
17831850
"CreateOrAlterKeyspaceRequest" : {
17841851
"type" : "object",
17851852
"properties" : {
Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
/*
2+
* Copyright DataStax, Inc.
3+
*
4+
* Please see the included license file for details.
5+
*/
6+
package com.datastax.mgmtapi.resources.models;
7+
8+
import com.fasterxml.jackson.annotation.JsonCreator;
9+
import com.fasterxml.jackson.annotation.JsonProperty;
10+
import com.fasterxml.jackson.core.JsonProcessingException;
11+
import com.fasterxml.jackson.databind.ObjectMapper;
12+
import java.util.Map;
13+
import java.util.Objects;
14+
15+
/**
16+
* Describes the state of an active compaction running on the server.
17+
*
18+
* <p>Some fields are specific to certain Cassandra versions, this is indicated in their comment.
19+
*/
20+
public class Compaction {
21+
22+
// Note: for simplicity, we use the same keys in our JSON payload as the map returned by
23+
// Cassandra. These constants are used for both, do not change them or the corresponding JSON
24+
// fields will always be empty.
25+
private static final String ID_KEY = "id";
26+
private static final String KEYSPACE_KEY = "keyspace";
27+
private static final String COLUMN_FAMILY_KEY = "columnfamily";
28+
private static final String COMPLETED_KEY = "completed";
29+
private static final String TOTAL_KEY = "total";
30+
private static final String TASK_TYPE_KEY = "taskType";
31+
private static final String UNIT_KEY = "unit";
32+
private static final String COMPACTION_ID_KEY = "compactionId";
33+
private static final String SSTABLES_KEY = "sstables";
34+
private static final String TARGET_DIRECTORY_KEY = "targetDirectory";
35+
private static final String OPERATION_TYPE_KEY = "operationType";
36+
private static final String OPERATION_ID_KEY = "operationId";
37+
private static final String DESCRIPTION_KEY = "description";
38+
39+
@JsonProperty(ID_KEY)
40+
public final String id;
41+
42+
@JsonProperty(KEYSPACE_KEY)
43+
public final String keyspace;
44+
45+
@JsonProperty(COLUMN_FAMILY_KEY)
46+
public final String columnFamily;
47+
48+
@JsonProperty(COMPLETED_KEY)
49+
public final Long completed;
50+
51+
@JsonProperty(TOTAL_KEY)
52+
public final Long total;
53+
54+
/** Only present in OSS Cassandra. */
55+
@JsonProperty(TASK_TYPE_KEY)
56+
public final String taskType;
57+
58+
@JsonProperty(UNIT_KEY)
59+
public final String unit;
60+
61+
/** Only present in OSS Cassandra. */
62+
@JsonProperty(COMPACTION_ID_KEY)
63+
public final String compactionId;
64+
65+
/** Only present in OSS Cassandra 4 or above. */
66+
@JsonProperty(SSTABLES_KEY)
67+
public final String ssTables;
68+
69+
/** Only present in OSS Cassandra 5. */
70+
@JsonProperty(TARGET_DIRECTORY_KEY)
71+
public final String targetDirectory;
72+
73+
/** Only present in DSE. */
74+
@JsonProperty(OPERATION_TYPE_KEY)
75+
public final String operationType;
76+
77+
/** Only present in DSE. */
78+
@JsonProperty(OPERATION_ID_KEY)
79+
public final String operationId;
80+
81+
/** Only present in DSE 6.8. */
82+
@JsonProperty(DESCRIPTION_KEY)
83+
public final String description;
84+
85+
@JsonCreator
86+
public Compaction(
87+
@JsonProperty(ID_KEY) String id,
88+
@JsonProperty(KEYSPACE_KEY) String keyspace,
89+
@JsonProperty(COLUMN_FAMILY_KEY) String columnFamily,
90+
@JsonProperty(COMPLETED_KEY) Long completed,
91+
@JsonProperty(TOTAL_KEY) Long total,
92+
@JsonProperty(TASK_TYPE_KEY) String taskType,
93+
@JsonProperty(UNIT_KEY) String unit,
94+
@JsonProperty(COMPACTION_ID_KEY) String compactionId,
95+
@JsonProperty(SSTABLES_KEY) String ssTables,
96+
@JsonProperty(TARGET_DIRECTORY_KEY) String targetDirectory,
97+
@JsonProperty(OPERATION_TYPE_KEY) String operationType,
98+
@JsonProperty(OPERATION_ID_KEY) String operationId,
99+
@JsonProperty(DESCRIPTION_KEY) String description) {
100+
101+
this.id = id;
102+
this.keyspace = keyspace;
103+
this.columnFamily = columnFamily;
104+
this.completed = completed;
105+
this.total = total;
106+
this.taskType = taskType;
107+
this.unit = unit;
108+
this.compactionId = compactionId;
109+
this.ssTables = ssTables;
110+
this.targetDirectory = targetDirectory;
111+
this.operationId = operationId;
112+
this.operationType = operationType;
113+
this.description = description;
114+
}
115+
116+
public static Compaction fromMap(Map<String, String> m) {
117+
return new Compaction(
118+
m.get(ID_KEY),
119+
m.get(KEYSPACE_KEY),
120+
m.get(COLUMN_FAMILY_KEY),
121+
parseLongOrNull(m.get(COMPLETED_KEY)),
122+
parseLongOrNull(m.get(TOTAL_KEY)),
123+
m.get(TASK_TYPE_KEY),
124+
m.get(UNIT_KEY),
125+
m.get(COMPACTION_ID_KEY),
126+
m.get(SSTABLES_KEY),
127+
m.get(TARGET_DIRECTORY_KEY),
128+
m.get(OPERATION_TYPE_KEY),
129+
m.get(OPERATION_ID_KEY),
130+
m.get(DESCRIPTION_KEY));
131+
}
132+
133+
private static Long parseLongOrNull(String s) {
134+
try {
135+
return Long.parseLong(s);
136+
} catch (NumberFormatException e) {
137+
return null;
138+
}
139+
}
140+
141+
@Override
142+
public boolean equals(Object o) {
143+
if (this == o) {
144+
return true;
145+
}
146+
if (o == null || getClass() != o.getClass()) {
147+
return false;
148+
}
149+
Compaction that = (Compaction) o;
150+
return Objects.equals(id, that.id)
151+
&& Objects.equals(keyspace, that.keyspace)
152+
&& Objects.equals(columnFamily, that.columnFamily)
153+
&& Objects.equals(completed, that.completed)
154+
&& Objects.equals(total, that.total)
155+
&& Objects.equals(taskType, that.taskType)
156+
&& Objects.equals(unit, that.unit)
157+
&& Objects.equals(compactionId, that.compactionId)
158+
&& Objects.equals(ssTables, that.ssTables)
159+
&& Objects.equals(targetDirectory, that.targetDirectory)
160+
&& Objects.equals(operationType, that.operationType)
161+
&& Objects.equals(operationId, that.operationId)
162+
&& Objects.equals(description, that.description);
163+
}
164+
165+
@Override
166+
public int hashCode() {
167+
return Objects.hash(
168+
id,
169+
keyspace,
170+
columnFamily,
171+
completed,
172+
total,
173+
taskType,
174+
unit,
175+
compactionId,
176+
ssTables,
177+
targetDirectory,
178+
operationType,
179+
operationId,
180+
description);
181+
}
182+
183+
@Override
184+
public String toString() {
185+
try {
186+
return new ObjectMapper().writeValueAsString(this);
187+
} catch (JsonProcessingException je) {
188+
return String.format("Unable to format compaction (%s)", je.getMessage());
189+
}
190+
}
191+
}

management-api-server/src/main/java/com/datastax/mgmtapi/resources/v1/TableOpsResources.java

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,13 @@
99
import com.datastax.mgmtapi.resources.common.BaseResources;
1010
import com.datastax.mgmtapi.resources.helpers.ResponseTools;
1111
import com.datastax.mgmtapi.resources.models.CompactRequest;
12+
import com.datastax.mgmtapi.resources.models.Compaction;
1213
import com.datastax.mgmtapi.resources.models.KeyspaceRequest;
1314
import com.datastax.mgmtapi.resources.models.ScrubRequest;
1415
import com.datastax.mgmtapi.resources.models.Table;
1516
import com.datastax.oss.driver.api.core.cql.ResultSet;
1617
import com.datastax.oss.driver.api.core.cql.Row;
18+
import com.datastax.oss.driver.api.core.type.reflect.GenericType;
1719
import com.google.common.collect.Lists;
1820
import io.swagger.v3.oas.annotations.Operation;
1921
import io.swagger.v3.oas.annotations.Parameter;
@@ -24,6 +26,8 @@
2426
import io.swagger.v3.oas.annotations.responses.ApiResponse;
2527
import java.util.ArrayList;
2628
import java.util.List;
29+
import java.util.Map;
30+
import java.util.stream.Collectors;
2731
import javax.ws.rs.Consumes;
2832
import javax.ws.rs.GET;
2933
import javax.ws.rs.POST;
@@ -39,6 +43,9 @@
3943
@Path("/api/v1/ops/tables")
4044
public class TableOpsResources extends BaseResources {
4145

46+
private static final GenericType<List<Map<String, String>>> LIST_OF_MAP_OF_STRINGS =
47+
GenericType.listOf(GenericType.mapOf(String.class, String.class));
48+
4249
public TableOpsResources(ManagementApplication application) {
4350
super(application);
4451
}
@@ -236,6 +243,33 @@ public Response compact(CompactRequest compactRequest) {
236243
});
237244
}
238245

246+
@GET
247+
@Path("/compactions")
248+
@Operation(summary = "Returns active compactions", operationId = "getCompactions")
249+
@Consumes(MediaType.APPLICATION_JSON)
250+
@Produces(MediaType.APPLICATION_JSON)
251+
@ApiResponse(
252+
responseCode = "200",
253+
description = "Compactions",
254+
content =
255+
@Content(
256+
mediaType = MediaType.APPLICATION_JSON,
257+
array = @ArraySchema(schema = @Schema(implementation = Compaction.class))))
258+
public Response getCompactions() {
259+
return handle(
260+
() -> {
261+
ResultSet result =
262+
app.cqlService.executeCql(app.dbUnixSocketFile, "CALL NodeOps.getCompactions()");
263+
Row row = result.one();
264+
assert row != null;
265+
List<Compaction> compactions =
266+
row.get(0, LIST_OF_MAP_OF_STRINGS).stream()
267+
.map(Compaction::fromMap)
268+
.collect(Collectors.toList());
269+
return Response.ok(compactions, MediaType.APPLICATION_JSON).build();
270+
});
271+
}
272+
239273
@GET
240274
@Produces({MediaType.TEXT_PLAIN, MediaType.APPLICATION_JSON})
241275
@ApiResponse(

0 commit comments

Comments
 (0)