use of org.apache.kafka.common.quota.ClientQuotaEntity in project kafka by apache.
the class ClientQuotaControlManager method alterClientQuotaEntity.
private void alterClientQuotaEntity(ClientQuotaEntity entity, Map<String, Double> newQuotaConfigs, List<ApiMessageAndVersion> outputRecords, Map<ClientQuotaEntity, ApiError> outputResults) {
// Check entity types and sanitize the names
Map<String, String> validatedEntityMap = new HashMap<>(3);
ApiError error = validateEntity(entity, validatedEntityMap);
if (error.isFailure()) {
outputResults.put(entity, error);
return;
}
// Check the combination of entity types and get the config keys
Map<String, ConfigDef.ConfigKey> configKeys = new HashMap<>(4);
error = configKeysForEntityType(validatedEntityMap, configKeys);
if (error.isFailure()) {
outputResults.put(entity, error);
return;
}
// Don't share objects between different records
Supplier<List<EntityData>> recordEntitySupplier = () -> validatedEntityMap.entrySet().stream().map(mapEntry -> new EntityData().setEntityType(mapEntry.getKey()).setEntityName(mapEntry.getValue())).collect(Collectors.toList());
List<ApiMessageAndVersion> newRecords = new ArrayList<>(newQuotaConfigs.size());
Map<String, Double> currentQuotas = clientQuotaData.containsKey(entity) ? clientQuotaData.get(entity) : Collections.emptyMap();
for (Map.Entry<String, Double> entry : newQuotaConfigs.entrySet()) {
String key = entry.getKey();
Double newValue = entry.getValue();
if (newValue == null) {
if (currentQuotas.containsKey(key)) {
// Null value indicates removal
newRecords.add(new ApiMessageAndVersion(new ClientQuotaRecord().setEntity(recordEntitySupplier.get()).setKey(key).setRemove(true), CLIENT_QUOTA_RECORD.highestSupportedVersion()));
}
} else {
ApiError validationError = validateQuotaKeyValue(configKeys, key, newValue);
if (validationError.isFailure()) {
outputResults.put(entity, validationError);
return;
} else {
final Double currentValue = currentQuotas.get(key);
if (!Objects.equals(currentValue, newValue)) {
// Only record the new value if it has changed
newRecords.add(new ApiMessageAndVersion(new ClientQuotaRecord().setEntity(recordEntitySupplier.get()).setKey(key).setValue(newValue), CLIENT_QUOTA_RECORD.highestSupportedVersion()));
}
}
}
}
outputRecords.addAll(newRecords);
outputResults.put(entity, ApiError.NONE);
}
use of org.apache.kafka.common.quota.ClientQuotaEntity in project kafka by apache.
the class ClientQuotaControlManager method replay.
/**
* Apply a quota record to the in-memory state.
*
* @param record A ClientQuotaRecord instance.
*/
public void replay(ClientQuotaRecord record) {
Map<String, String> entityMap = new HashMap<>(2);
record.entity().forEach(entityData -> entityMap.put(entityData.entityType(), entityData.entityName()));
ClientQuotaEntity entity = new ClientQuotaEntity(entityMap);
TimelineHashMap<String, Double> quotas = clientQuotaData.get(entity);
if (quotas == null) {
quotas = new TimelineHashMap<>(snapshotRegistry, 0);
clientQuotaData.put(entity, quotas);
}
if (record.remove()) {
quotas.remove(record.key());
if (quotas.size() == 0) {
clientQuotaData.remove(entity);
}
} else {
quotas.put(record.key(), record.value());
}
}
use of org.apache.kafka.common.quota.ClientQuotaEntity in project kafka by apache.
the class ClientQuotaControlManagerTest method testAlterAndRemove.
@Test
public void testAlterAndRemove() {
SnapshotRegistry snapshotRegistry = new SnapshotRegistry(new LogContext());
ClientQuotaControlManager manager = new ClientQuotaControlManager(snapshotRegistry);
ClientQuotaEntity userEntity = userEntity("user-1");
List<ClientQuotaAlteration> alters = new ArrayList<>();
// Add one quota
entityQuotaToAlterations(userEntity, quotas(QuotaConfigs.PRODUCER_BYTE_RATE_OVERRIDE_CONFIG, 10000.0), alters::add);
alterQuotas(alters, manager);
assertEquals(1, manager.clientQuotaData.get(userEntity).size());
assertEquals(10000.0, manager.clientQuotaData.get(userEntity).get(QuotaConfigs.PRODUCER_BYTE_RATE_OVERRIDE_CONFIG), 1e-6);
// Replace it and add another
alters.clear();
entityQuotaToAlterations(userEntity, quotas(QuotaConfigs.PRODUCER_BYTE_RATE_OVERRIDE_CONFIG, 10001.0, QuotaConfigs.CONSUMER_BYTE_RATE_OVERRIDE_CONFIG, 20000.0), alters::add);
alterQuotas(alters, manager);
assertEquals(2, manager.clientQuotaData.get(userEntity).size());
assertEquals(10001.0, manager.clientQuotaData.get(userEntity).get(QuotaConfigs.PRODUCER_BYTE_RATE_OVERRIDE_CONFIG), 1e-6);
assertEquals(20000.0, manager.clientQuotaData.get(userEntity).get(QuotaConfigs.CONSUMER_BYTE_RATE_OVERRIDE_CONFIG), 1e-6);
// Remove one of the quotas, the other remains
alters.clear();
entityQuotaToAlterations(userEntity, quotas(QuotaConfigs.PRODUCER_BYTE_RATE_OVERRIDE_CONFIG, null), alters::add);
alterQuotas(alters, manager);
assertEquals(1, manager.clientQuotaData.get(userEntity).size());
assertEquals(20000.0, manager.clientQuotaData.get(userEntity).get(QuotaConfigs.CONSUMER_BYTE_RATE_OVERRIDE_CONFIG), 1e-6);
// Remove non-existent quota, no change
alters.clear();
entityQuotaToAlterations(userEntity, quotas(QuotaConfigs.REQUEST_PERCENTAGE_OVERRIDE_CONFIG, null), alters::add);
alterQuotas(alters, manager);
assertEquals(1, manager.clientQuotaData.get(userEntity).size());
assertEquals(20000.0, manager.clientQuotaData.get(userEntity).get(QuotaConfigs.CONSUMER_BYTE_RATE_OVERRIDE_CONFIG), 1e-6);
// All quotas removed, we should cleanup the map
alters.clear();
entityQuotaToAlterations(userEntity, quotas(QuotaConfigs.CONSUMER_BYTE_RATE_OVERRIDE_CONFIG, null), alters::add);
alterQuotas(alters, manager);
assertFalse(manager.clientQuotaData.containsKey(userEntity));
// Remove non-existent quota, again no change
alters.clear();
entityQuotaToAlterations(userEntity, quotas(QuotaConfigs.CONSUMER_BYTE_RATE_OVERRIDE_CONFIG, null), alters::add);
alterQuotas(alters, manager);
assertFalse(manager.clientQuotaData.containsKey(userEntity));
// Mixed update
alters.clear();
Map<String, Double> quotas = new HashMap<>(4);
quotas.put(QuotaConfigs.REQUEST_PERCENTAGE_OVERRIDE_CONFIG, 99.0);
quotas.put(QuotaConfigs.CONTROLLER_MUTATION_RATE_OVERRIDE_CONFIG, null);
quotas.put(QuotaConfigs.PRODUCER_BYTE_RATE_OVERRIDE_CONFIG, 10002.0);
quotas.put(QuotaConfigs.CONSUMER_BYTE_RATE_OVERRIDE_CONFIG, 20001.0);
entityQuotaToAlterations(userEntity, quotas, alters::add);
alterQuotas(alters, manager);
assertEquals(3, manager.clientQuotaData.get(userEntity).size());
assertEquals(20001.0, manager.clientQuotaData.get(userEntity).get(QuotaConfigs.CONSUMER_BYTE_RATE_OVERRIDE_CONFIG), 1e-6);
assertEquals(10002.0, manager.clientQuotaData.get(userEntity).get(QuotaConfigs.PRODUCER_BYTE_RATE_OVERRIDE_CONFIG), 1e-6);
assertEquals(99.0, manager.clientQuotaData.get(userEntity).get(QuotaConfigs.REQUEST_PERCENTAGE_OVERRIDE_CONFIG), 1e-6);
}
use of org.apache.kafka.common.quota.ClientQuotaEntity in project kafka by apache.
the class ClientQuotaControlManagerTest method entityQuotaToAlterations.
static void entityQuotaToAlterations(ClientQuotaEntity entity, Map<String, Double> quota, Consumer<ClientQuotaAlteration> acceptor) {
Collection<ClientQuotaAlteration.Op> ops = quota.entrySet().stream().map(quotaEntry -> new ClientQuotaAlteration.Op(quotaEntry.getKey(), quotaEntry.getValue())).collect(Collectors.toList());
acceptor.accept(new ClientQuotaAlteration(entity, ops));
}
use of org.apache.kafka.common.quota.ClientQuotaEntity in project kafka by apache.
the class ClientQuotaControlManagerTest method testEntityTypes.
@Test
public void testEntityTypes() throws Exception {
SnapshotRegistry snapshotRegistry = new SnapshotRegistry(new LogContext());
ClientQuotaControlManager manager = new ClientQuotaControlManager(snapshotRegistry);
Map<ClientQuotaEntity, Map<String, Double>> quotasToTest = new HashMap<>();
quotasToTest.put(userClientEntity("user-1", "client-id-1"), quotas(QuotaConfigs.REQUEST_PERCENTAGE_OVERRIDE_CONFIG, 50.50));
quotasToTest.put(userClientEntity("user-2", "client-id-1"), quotas(QuotaConfigs.REQUEST_PERCENTAGE_OVERRIDE_CONFIG, 51.51));
quotasToTest.put(userClientEntity("user-3", "client-id-2"), quotas(QuotaConfigs.REQUEST_PERCENTAGE_OVERRIDE_CONFIG, 52.52));
quotasToTest.put(userClientEntity(null, "client-id-1"), quotas(QuotaConfigs.REQUEST_PERCENTAGE_OVERRIDE_CONFIG, 53.53));
quotasToTest.put(userClientEntity("user-1", null), quotas(QuotaConfigs.REQUEST_PERCENTAGE_OVERRIDE_CONFIG, 54.54));
quotasToTest.put(userClientEntity("user-3", null), quotas(QuotaConfigs.REQUEST_PERCENTAGE_OVERRIDE_CONFIG, 55.55));
quotasToTest.put(userEntity("user-1"), quotas(QuotaConfigs.REQUEST_PERCENTAGE_OVERRIDE_CONFIG, 56.56));
quotasToTest.put(userEntity("user-2"), quotas(QuotaConfigs.REQUEST_PERCENTAGE_OVERRIDE_CONFIG, 57.57));
quotasToTest.put(userEntity("user-3"), quotas(QuotaConfigs.REQUEST_PERCENTAGE_OVERRIDE_CONFIG, 58.58));
quotasToTest.put(userEntity(null), quotas(QuotaConfigs.REQUEST_PERCENTAGE_OVERRIDE_CONFIG, 59.59));
quotasToTest.put(clientEntity("client-id-2"), quotas(QuotaConfigs.REQUEST_PERCENTAGE_OVERRIDE_CONFIG, 60.60));
List<ClientQuotaAlteration> alters = new ArrayList<>();
quotasToTest.forEach((entity, quota) -> entityQuotaToAlterations(entity, quota, alters::add));
alterQuotas(alters, manager);
RecordTestUtils.assertBatchIteratorContains(Arrays.asList(Arrays.asList(new ApiMessageAndVersion(new ClientQuotaRecord().setEntity(Arrays.asList(new EntityData().setEntityType("user").setEntityName("user-1"), new EntityData().setEntityType("client-id").setEntityName("client-id-1"))).setKey("request_percentage").setValue(50.5).setRemove(false), (short) 0)), Arrays.asList(new ApiMessageAndVersion(new ClientQuotaRecord().setEntity(Arrays.asList(new EntityData().setEntityType("user").setEntityName("user-2"), new EntityData().setEntityType("client-id").setEntityName("client-id-1"))).setKey("request_percentage").setValue(51.51).setRemove(false), (short) 0)), Arrays.asList(new ApiMessageAndVersion(new ClientQuotaRecord().setEntity(Arrays.asList(new EntityData().setEntityType("user").setEntityName("user-3"), new EntityData().setEntityType("client-id").setEntityName("client-id-2"))).setKey("request_percentage").setValue(52.52).setRemove(false), (short) 0)), Arrays.asList(new ApiMessageAndVersion(new ClientQuotaRecord().setEntity(Arrays.asList(new EntityData().setEntityType("user").setEntityName(null), new EntityData().setEntityType("client-id").setEntityName("client-id-1"))).setKey("request_percentage").setValue(53.53).setRemove(false), (short) 0)), Arrays.asList(new ApiMessageAndVersion(new ClientQuotaRecord().setEntity(Arrays.asList(new EntityData().setEntityType("user").setEntityName("user-1"), new EntityData().setEntityType("client-id").setEntityName(null))).setKey("request_percentage").setValue(54.54).setRemove(false), (short) 0)), Arrays.asList(new ApiMessageAndVersion(new ClientQuotaRecord().setEntity(Arrays.asList(new EntityData().setEntityType("user").setEntityName("user-3"), new EntityData().setEntityType("client-id").setEntityName(null))).setKey("request_percentage").setValue(55.55).setRemove(false), (short) 0)), Arrays.asList(new ApiMessageAndVersion(new ClientQuotaRecord().setEntity(Arrays.asList(new EntityData().setEntityType("user").setEntityName("user-1"))).setKey("request_percentage").setValue(56.56).setRemove(false), (short) 0)), Arrays.asList(new ApiMessageAndVersion(new ClientQuotaRecord().setEntity(Arrays.asList(new EntityData().setEntityType("user").setEntityName("user-2"))).setKey("request_percentage").setValue(57.57).setRemove(false), (short) 0)), Arrays.asList(new ApiMessageAndVersion(new ClientQuotaRecord().setEntity(Arrays.asList(new EntityData().setEntityType("user").setEntityName("user-3"))).setKey("request_percentage").setValue(58.58).setRemove(false), (short) 0)), Arrays.asList(new ApiMessageAndVersion(new ClientQuotaRecord().setEntity(Arrays.asList(new EntityData().setEntityType("user").setEntityName(null))).setKey("request_percentage").setValue(59.59).setRemove(false), (short) 0)), Arrays.asList(new ApiMessageAndVersion(new ClientQuotaRecord().setEntity(Arrays.asList(new EntityData().setEntityType("client-id").setEntityName("client-id-2"))).setKey("request_percentage").setValue(60.60).setRemove(false), (short) 0))), manager.iterator(Long.MAX_VALUE));
}
Aggregations