Skip to content

Commit

Permalink
Add PartialRuleUpdateSupported feature and try in encrypt rule first (#…
Browse files Browse the repository at this point in the history
…31162)

* Add PartialRuleUpdateSupported feature and try in encrypt rule first

* Add PartialRuleUpdateSupported feature and try in encrypt rule first
  • Loading branch information
terrymanu authored May 7, 2024
1 parent 1d158d4 commit 043963d
Show file tree
Hide file tree
Showing 3 changed files with 132 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

package org.apache.shardingsphere.encrypt.rule;

import com.google.common.base.Preconditions;
import lombok.Getter;
import org.apache.shardingsphere.encrypt.api.config.EncryptRuleConfiguration;
import org.apache.shardingsphere.encrypt.api.config.rule.EncryptColumnRuleConfiguration;
Expand All @@ -25,27 +26,31 @@
import org.apache.shardingsphere.encrypt.exception.metadata.MismatchedEncryptAlgorithmTypeException;
import org.apache.shardingsphere.encrypt.rule.attribute.EncryptTableMapperRuleAttribute;
import org.apache.shardingsphere.encrypt.spi.EncryptAlgorithm;
import org.apache.shardingsphere.infra.algorithm.core.config.AlgorithmConfiguration;
import org.apache.shardingsphere.infra.exception.core.ShardingSpherePreconditions;
import org.apache.shardingsphere.infra.rule.PartialRuleUpdateSupported;
import org.apache.shardingsphere.infra.rule.attribute.RuleAttributes;
import org.apache.shardingsphere.infra.rule.scope.DatabaseRule;
import org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader;

import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

/**
* Encrypt rule.
*/
public final class EncryptRule implements DatabaseRule {
public final class EncryptRule implements DatabaseRule, PartialRuleUpdateSupported<EncryptRuleConfiguration> {

private final String databaseName;

@Getter
private final EncryptRuleConfiguration configuration;
private final AtomicReference<EncryptRuleConfiguration> ruleConfig = new AtomicReference<>();

private final Map<String, EncryptTable> tables;

Expand All @@ -54,8 +59,8 @@ public final class EncryptRule implements DatabaseRule {

public EncryptRule(final String databaseName, final EncryptRuleConfiguration ruleConfig) {
this.databaseName = databaseName;
configuration = ruleConfig;
tables = new LinkedHashMap<>();
this.ruleConfig.set(ruleConfig);
tables = new ConcurrentHashMap<>();
Map<String, EncryptAlgorithm> encryptors = ruleConfig.getEncryptors().entrySet().stream()
.collect(Collectors.toMap(Entry::getKey, entry -> TypedSPILoader.getService(EncryptAlgorithm.class, entry.getValue().getType(), entry.getValue().getProps())));
for (EncryptTableRuleConfiguration each : ruleConfig.getTables()) {
Expand Down Expand Up @@ -107,4 +112,60 @@ public EncryptTable getEncryptTable(final String tableName) {
ShardingSpherePreconditions.checkState(encryptTable.isPresent(), () -> new EncryptTableNotFoundException(tableName));
return encryptTable.get();
}

@Override
public EncryptRuleConfiguration getConfiguration() {
return ruleConfig.get();
}

@Override
public void updateConfiguration(final EncryptRuleConfiguration toBeUpdatedRuleConfig) {
ruleConfig.set(toBeUpdatedRuleConfig);
}

@Override
public boolean partialUpdateRule(final EncryptRuleConfiguration toBeUpdatedRuleConfig) {
Collection<String> toBeAddedTableNames = toBeUpdatedRuleConfig.getTables().stream().map(EncryptTableRuleConfiguration::getName).collect(Collectors.toList());
toBeAddedTableNames.removeAll(tables.keySet());
if (!toBeAddedTableNames.isEmpty()) {
for (String each : toBeAddedTableNames) {
EncryptTableRuleConfiguration tableRuleConfig = getEncryptTableRuleConfiguration(each, toBeUpdatedRuleConfig);
Map<String, AlgorithmConfiguration> encryptorConfigs = getEncryptorConfigurations(tableRuleConfig, toBeUpdatedRuleConfig.getEncryptors());
Map<String, EncryptAlgorithm> encryptors = encryptorConfigs.entrySet().stream()
.collect(Collectors.toMap(Entry::getKey, entry -> TypedSPILoader.getService(EncryptAlgorithm.class, entry.getValue().getType(), entry.getValue().getProps())));
tableRuleConfig.getColumns().forEach(columnRuleConfig -> checkEncryptorType(columnRuleConfig, encryptors));
tables.put(each.toLowerCase(), new EncryptTable(tableRuleConfig, encryptors));
}
return true;
}
Collection<String> toBeRemovedTableNames = new HashSet<>(tables.keySet());
toBeRemovedTableNames.removeAll(toBeUpdatedRuleConfig.getTables().stream().map(EncryptTableRuleConfiguration::getName).collect(Collectors.toList()));
if (!toBeRemovedTableNames.isEmpty()) {
toBeRemovedTableNames.stream().map(String::toLowerCase).forEach(tables::remove);
return true;
}
// TODO Process update table
// TODO Process update encryptors
return false;
}

private EncryptTableRuleConfiguration getEncryptTableRuleConfiguration(final String tableName, final EncryptRuleConfiguration toBeUpdatedRuleConfig) {
Optional<EncryptTableRuleConfiguration> result = toBeUpdatedRuleConfig.getTables().stream().filter(table -> table.getName().equals(tableName)).findFirst();
Preconditions.checkState(result.isPresent());
return result.get();
}

private Map<String, AlgorithmConfiguration> getEncryptorConfigurations(final EncryptTableRuleConfiguration tableRuleConfig, final Map<String, AlgorithmConfiguration> encryptors) {
Map<String, AlgorithmConfiguration> result = new HashMap<>(encryptors.size(), 1F);
for (EncryptColumnRuleConfiguration each : tableRuleConfig.getColumns()) {
result.put(each.getCipher().getEncryptorName(), encryptors.get(each.getCipher().getEncryptorName()));
if (each.getAssistedQuery().isPresent()) {
result.put(each.getAssistedQuery().get().getEncryptorName(), encryptors.get(each.getAssistedQuery().get().getEncryptorName()));
}
if (each.getLikeQuery().isPresent()) {
result.put(each.getLikeQuery().get().getEncryptorName(), encryptors.get(each.getLikeQuery().get().getEncryptorName()));
}
}
return result;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.shardingsphere.infra.rule;

import org.apache.shardingsphere.infra.config.rule.RuleConfiguration;

/**
* Partial rule update supported.
*
* @param <T> rule configuration type
*/
public interface PartialRuleUpdateSupported<T extends RuleConfiguration> {

/**
* Update rule configuration.
*
* @param toBeUpdatedRuleConfig to be updated configuration
*/
void updateConfiguration(T toBeUpdatedRuleConfig);

/**
* Partial update.
*
* @param toBeUpdatedRuleConfig to be updated configuration
* @return update success or not
*/
// TODO remove return value when support alter
boolean partialUpdateRule(T toBeUpdatedRuleConfig);
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
import org.apache.shardingsphere.infra.metadata.database.rule.RuleMetaData;
import org.apache.shardingsphere.infra.metadata.database.schema.manager.GenericSchemaManager;
import org.apache.shardingsphere.infra.metadata.database.schema.model.ShardingSphereSchema;
import org.apache.shardingsphere.infra.rule.PartialRuleUpdateSupported;
import org.apache.shardingsphere.infra.rule.ShardingSphereRule;
import org.apache.shardingsphere.infra.rule.builder.database.DatabaseRulesBuilder;
import org.apache.shardingsphere.infra.rule.builder.global.GlobalRulesBuilder;
Expand Down Expand Up @@ -154,15 +155,18 @@ private void persistSchemaMetaData(final String databaseName, final MetaDataCont
* @param databaseName database name
* @param ruleConfig rule configurations
*/
@SuppressWarnings({"unchecked", "rawtypes"})
public synchronized void alterRuleConfiguration(final String databaseName, final RuleConfiguration ruleConfig) {
// TODO add feature for partly refresh
// 1. Judge if impl partly interface
// 2. compare diff with current and ruleConfig
// 3. Do partly refresh
// 4. return
ShardingSphereDatabase database = metaDataContexts.get().getMetaData().getDatabase(databaseName);
Collection<ShardingSphereRule> rules = new LinkedList<>(database.getRuleMetaData().getRules());
Optional<ShardingSphereRule> toBeChangedRule = rules.stream().filter(each -> each.getConfiguration().getClass().equals(ruleConfig.getClass())).findFirst();
if (toBeChangedRule.isPresent() && toBeChangedRule.get() instanceof PartialRuleUpdateSupported) {
if (((PartialRuleUpdateSupported) toBeChangedRule.get()).partialUpdateRule(ruleConfig)) {
((PartialRuleUpdateSupported) toBeChangedRule.get()).updateConfiguration(ruleConfig);
return;
}
}
try {
ShardingSphereDatabase database = metaDataContexts.get().getMetaData().getDatabase(databaseName);
Collection<ShardingSphereRule> rules = new LinkedList<>(database.getRuleMetaData().getRules());
rules.removeIf(each -> each.getConfiguration().getClass().isAssignableFrom(ruleConfig.getClass()));
rules.addAll(DatabaseRulesBuilder.build(databaseName, database.getProtocolType(),
database.getResourceMetaData().getStorageUnits().entrySet().stream()
Expand All @@ -180,15 +184,18 @@ public synchronized void alterRuleConfiguration(final String databaseName, final
* @param databaseName database name
* @param ruleConfig rule configurations
*/
@SuppressWarnings({"unchecked", "rawtypes"})
public synchronized void dropRuleConfiguration(final String databaseName, final RuleConfiguration ruleConfig) {
// TODO add feature for partly refresh
// 1. Judge if impl partly interface
// 2. compare diff with current and ruleConfig
// 3. Remove to be removed partial config
// 4. return
ShardingSphereDatabase database = metaDataContexts.get().getMetaData().getDatabase(databaseName);
Collection<ShardingSphereRule> rules = new LinkedList<>(database.getRuleMetaData().getRules());
Optional<ShardingSphereRule> toBeChangedRule = rules.stream().filter(each -> each.getConfiguration().getClass().equals(ruleConfig.getClass())).findFirst();
if (toBeChangedRule.isPresent() && toBeChangedRule.get() instanceof PartialRuleUpdateSupported) {
if (((PartialRuleUpdateSupported) toBeChangedRule.get()).partialUpdateRule(ruleConfig)) {
((PartialRuleUpdateSupported) toBeChangedRule.get()).updateConfiguration(ruleConfig);
return;
}
}
try {
ShardingSphereDatabase database = metaDataContexts.get().getMetaData().getDatabase(databaseName);
Collection<ShardingSphereRule> rules = new LinkedList<>(database.getRuleMetaData().getRules());
rules.removeIf(each -> each.getConfiguration().getClass().isAssignableFrom(ruleConfig.getClass()));
if (!((DatabaseRuleConfiguration) ruleConfig).isEmpty()) {
rules.addAll(DatabaseRulesBuilder.build(databaseName, database.getProtocolType(),
Expand Down

0 comments on commit 043963d

Please sign in to comment.