Skip to content

Commit

Permalink
Add operation to get active compactions (fixes #364) (#365)
Browse files Browse the repository at this point in the history
  • Loading branch information
olim7t authored Aug 30, 2023
1 parent 5506d26 commit da8d906
Show file tree
Hide file tree
Showing 4 changed files with 298 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -381,6 +381,12 @@ public String forceKeyspaceCompaction(
return submitJob(OperationType.COMPACTION.name(), compactionOperation, async);
}

@Rpc(name = "getCompactions")
public List<Map<String, String>> getCompactions() {
logger.debug("Getting active compactions");
return ShimLoader.instance.get().getCompactionManager().getCompactions();
}

@Rpc(name = "garbageCollect")
public void garbageCollect(
@RpcParam(name = "tombstoneOption") String tombstoneOption,
Expand Down
67 changes: 67 additions & 0 deletions management-api-server/doc/openapi.json
Original file line number Diff line number Diff line change
Expand Up @@ -1657,6 +1657,27 @@
"summary" : "Force a (major) compaction on one or more tables or user-defined compaction on given SSTables"
}
},
"/api/v1/ops/tables/compactions" : {
"get" : {
"operationId" : "getCompactions",
"responses" : {
"200" : {
"content" : {
"application/json" : {
"schema" : {
"type" : "array",
"items" : {
"$ref" : "#/components/schemas/Compaction"
}
}
}
},
"description" : "Compactions"
}
},
"summary" : "Returns active compactions"
}
},
"/api/v1/ops/tables/scrub" : {
"post" : {
"operationId" : "scrub_1",
Expand Down Expand Up @@ -1780,6 +1801,52 @@
},
"required" : [ "keyspace_name", "split_output", "user_defined" ]
},
"Compaction" : {
"type" : "object",
"properties" : {
"columnfamily" : {
"type" : "string"
},
"compactionId" : {
"type" : "string"
},
"completed" : {
"type" : "integer",
"format" : "int64"
},
"description" : {
"type" : "string"
},
"id" : {
"type" : "string"
},
"keyspace" : {
"type" : "string"
},
"operationId" : {
"type" : "string"
},
"operationType" : {
"type" : "string"
},
"sstables" : {
"type" : "string"
},
"targetDirectory" : {
"type" : "string"
},
"taskType" : {
"type" : "string"
},
"total" : {
"type" : "integer",
"format" : "int64"
},
"unit" : {
"type" : "string"
}
}
},
"CreateOrAlterKeyspaceRequest" : {
"type" : "object",
"properties" : {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
/*
* Copyright DataStax, Inc.
*
* Please see the included license file for details.
*/
package com.datastax.mgmtapi.resources.models;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.Map;
import java.util.Objects;

/**
* Describes the state of an active compaction running on the server.
*
* <p>Some fields are specific to certain Cassandra versions, this is indicated in their comment.
*/
public class Compaction {

// Note: for simplicity, we use the same keys in our JSON payload as the map returned by
// Cassandra. These constants are used for both, do not change them or the corresponding JSON
// fields will always be empty.
private static final String ID_KEY = "id";
private static final String KEYSPACE_KEY = "keyspace";
private static final String COLUMN_FAMILY_KEY = "columnfamily";
private static final String COMPLETED_KEY = "completed";
private static final String TOTAL_KEY = "total";
private static final String TASK_TYPE_KEY = "taskType";
private static final String UNIT_KEY = "unit";
private static final String COMPACTION_ID_KEY = "compactionId";
private static final String SSTABLES_KEY = "sstables";
private static final String TARGET_DIRECTORY_KEY = "targetDirectory";
private static final String OPERATION_TYPE_KEY = "operationType";
private static final String OPERATION_ID_KEY = "operationId";
private static final String DESCRIPTION_KEY = "description";

@JsonProperty(ID_KEY)
public final String id;

@JsonProperty(KEYSPACE_KEY)
public final String keyspace;

@JsonProperty(COLUMN_FAMILY_KEY)
public final String columnFamily;

@JsonProperty(COMPLETED_KEY)
public final Long completed;

@JsonProperty(TOTAL_KEY)
public final Long total;

/** Only present in OSS Cassandra. */
@JsonProperty(TASK_TYPE_KEY)
public final String taskType;

@JsonProperty(UNIT_KEY)
public final String unit;

/** Only present in OSS Cassandra. */
@JsonProperty(COMPACTION_ID_KEY)
public final String compactionId;

/** Only present in OSS Cassandra 4 or above. */
@JsonProperty(SSTABLES_KEY)
public final String ssTables;

/** Only present in OSS Cassandra 5. */
@JsonProperty(TARGET_DIRECTORY_KEY)
public final String targetDirectory;

/** Only present in DSE. */
@JsonProperty(OPERATION_TYPE_KEY)
public final String operationType;

/** Only present in DSE. */
@JsonProperty(OPERATION_ID_KEY)
public final String operationId;

/** Only present in DSE 6.8. */
@JsonProperty(DESCRIPTION_KEY)
public final String description;

@JsonCreator
public Compaction(
@JsonProperty(ID_KEY) String id,
@JsonProperty(KEYSPACE_KEY) String keyspace,
@JsonProperty(COLUMN_FAMILY_KEY) String columnFamily,
@JsonProperty(COMPLETED_KEY) Long completed,
@JsonProperty(TOTAL_KEY) Long total,
@JsonProperty(TASK_TYPE_KEY) String taskType,
@JsonProperty(UNIT_KEY) String unit,
@JsonProperty(COMPACTION_ID_KEY) String compactionId,
@JsonProperty(SSTABLES_KEY) String ssTables,
@JsonProperty(TARGET_DIRECTORY_KEY) String targetDirectory,
@JsonProperty(OPERATION_TYPE_KEY) String operationType,
@JsonProperty(OPERATION_ID_KEY) String operationId,
@JsonProperty(DESCRIPTION_KEY) String description) {

this.id = id;
this.keyspace = keyspace;
this.columnFamily = columnFamily;
this.completed = completed;
this.total = total;
this.taskType = taskType;
this.unit = unit;
this.compactionId = compactionId;
this.ssTables = ssTables;
this.targetDirectory = targetDirectory;
this.operationId = operationId;
this.operationType = operationType;
this.description = description;
}

public static Compaction fromMap(Map<String, String> m) {
return new Compaction(
m.get(ID_KEY),
m.get(KEYSPACE_KEY),
m.get(COLUMN_FAMILY_KEY),
parseLongOrNull(m.get(COMPLETED_KEY)),
parseLongOrNull(m.get(TOTAL_KEY)),
m.get(TASK_TYPE_KEY),
m.get(UNIT_KEY),
m.get(COMPACTION_ID_KEY),
m.get(SSTABLES_KEY),
m.get(TARGET_DIRECTORY_KEY),
m.get(OPERATION_TYPE_KEY),
m.get(OPERATION_ID_KEY),
m.get(DESCRIPTION_KEY));
}

private static Long parseLongOrNull(String s) {
try {
return Long.parseLong(s);
} catch (NumberFormatException e) {
return null;
}
}

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Compaction that = (Compaction) o;
return Objects.equals(id, that.id)
&& Objects.equals(keyspace, that.keyspace)
&& Objects.equals(columnFamily, that.columnFamily)
&& Objects.equals(completed, that.completed)
&& Objects.equals(total, that.total)
&& Objects.equals(taskType, that.taskType)
&& Objects.equals(unit, that.unit)
&& Objects.equals(compactionId, that.compactionId)
&& Objects.equals(ssTables, that.ssTables)
&& Objects.equals(targetDirectory, that.targetDirectory)
&& Objects.equals(operationType, that.operationType)
&& Objects.equals(operationId, that.operationId)
&& Objects.equals(description, that.description);
}

@Override
public int hashCode() {
return Objects.hash(
id,
keyspace,
columnFamily,
completed,
total,
taskType,
unit,
compactionId,
ssTables,
targetDirectory,
operationType,
operationId,
description);
}

@Override
public String toString() {
try {
return new ObjectMapper().writeValueAsString(this);
} catch (JsonProcessingException je) {
return String.format("Unable to format compaction (%s)", je.getMessage());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,13 @@
import com.datastax.mgmtapi.resources.common.BaseResources;
import com.datastax.mgmtapi.resources.helpers.ResponseTools;
import com.datastax.mgmtapi.resources.models.CompactRequest;
import com.datastax.mgmtapi.resources.models.Compaction;
import com.datastax.mgmtapi.resources.models.KeyspaceRequest;
import com.datastax.mgmtapi.resources.models.ScrubRequest;
import com.datastax.mgmtapi.resources.models.Table;
import com.datastax.oss.driver.api.core.cql.ResultSet;
import com.datastax.oss.driver.api.core.cql.Row;
import com.datastax.oss.driver.api.core.type.reflect.GenericType;
import com.google.common.collect.Lists;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
Expand All @@ -24,6 +26,8 @@
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
Expand All @@ -39,6 +43,9 @@
@Path("/api/v1/ops/tables")
public class TableOpsResources extends BaseResources {

private static final GenericType<List<Map<String, String>>> LIST_OF_MAP_OF_STRINGS =
GenericType.listOf(GenericType.mapOf(String.class, String.class));

public TableOpsResources(ManagementApplication application) {
super(application);
}
Expand Down Expand Up @@ -236,6 +243,33 @@ public Response compact(CompactRequest compactRequest) {
});
}

@GET
@Path("/compactions")
@Operation(summary = "Returns active compactions", operationId = "getCompactions")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
@ApiResponse(
responseCode = "200",
description = "Compactions",
content =
@Content(
mediaType = MediaType.APPLICATION_JSON,
array = @ArraySchema(schema = @Schema(implementation = Compaction.class))))
public Response getCompactions() {
return handle(
() -> {
ResultSet result =
app.cqlService.executeCql(app.dbUnixSocketFile, "CALL NodeOps.getCompactions()");
Row row = result.one();
assert row != null;
List<Compaction> compactions =
row.get(0, LIST_OF_MAP_OF_STRINGS).stream()
.map(Compaction::fromMap)
.collect(Collectors.toList());
return Response.ok(compactions, MediaType.APPLICATION_JSON).build();
});
}

@GET
@Produces({MediaType.TEXT_PLAIN, MediaType.APPLICATION_JSON})
@ApiResponse(
Expand Down

0 comments on commit da8d906

Please sign in to comment.