Skip to content

Commit

Permalink
[ISSUE #13023]Add Unit Test for ConfigQueryHandlerChainn and optimize…
Browse files Browse the repository at this point in the history
… the logic (#13024)

 optimize Config Query Chain logic
  • Loading branch information
Sunrisea authored Jan 9, 2025
1 parent 3796395 commit 8a136c2
Show file tree
Hide file tree
Showing 16 changed files with 856 additions and 62 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@
import com.alibaba.nacos.config.server.model.ConfigCacheGray;
import com.alibaba.nacos.config.server.model.gray.BetaGrayRule;
import com.alibaba.nacos.config.server.model.gray.TagGrayRule;
import com.alibaba.nacos.config.server.service.LongPollingService;
import com.alibaba.nacos.config.server.service.query.ConfigChainRequestExtractorService;
import com.alibaba.nacos.config.server.service.query.ConfigQueryChainService;
import com.alibaba.nacos.config.server.service.LongPollingService;
import com.alibaba.nacos.config.server.service.query.enums.ResponseCode;
import com.alibaba.nacos.config.server.service.query.model.ConfigQueryChainRequest;
import com.alibaba.nacos.config.server.service.query.model.ConfigQueryChainResponse;
Expand Down Expand Up @@ -81,6 +81,12 @@ public ConfigServletInner(LongPollingService longPollingService, ConfigQueryChai
this.configQueryChainService = configQueryChainService;
}

private static String getDecryptContent(ConfigQueryChainResponse chainResponse, String dataId) {
Pair<String, String> pair = EncryptionHandler.decryptHandler(dataId, chainResponse.getEncryptedDataKey(),
chainResponse.getContent());
return pair.getSecond();
}

/**
* long polling the config.
*/
Expand Down Expand Up @@ -142,6 +148,7 @@ public String doGetConfig(HttpServletRequest request, HttpServletResponse respon

switch (chainResponse.getStatus()) {
case CONFIG_NOT_FOUND:
case SPECIAL_TAG_CONFIG_NOT_FOUND:
return handlerConfigNotFound(response, apiVersion);
case CONFIG_QUERY_CONFLICT:
return handlerConfigConflict(response, apiVersion);
Expand All @@ -162,9 +169,11 @@ private String handlerConfigNotFound(HttpServletResponse response, ApiVersionEnu
private String handlerConfigConflict(HttpServletResponse response, ApiVersionEnum apiVersion) throws IOException {
response.setStatus(HttpServletResponse.SC_CONFLICT);
if (apiVersion == ApiVersionEnum.V1) {
return writeResponseForV1(response, Result.failure(ErrorCode.RESOURCE_CONFLICT, "requested file is being modified, please try later."));
return writeResponseForV1(response,
Result.failure(ErrorCode.RESOURCE_CONFLICT, "requested file is being modified, please try later."));
} else {
return writeResponseForV2(response, Result.failure(ErrorCode.RESOURCE_CONFLICT, "requested file is being modified, please try later."));
return writeResponseForV2(response,
Result.failure(ErrorCode.RESOURCE_CONFLICT, "requested file is being modified, please try later."));
}
}

Expand Down Expand Up @@ -204,10 +213,11 @@ private String handleResponseForV2(HttpServletResponse response, ConfigQueryChai
}

private void setResponseHeadForV1(HttpServletResponse response, ConfigQueryChainResponse chainResponse) {
String contentType = chainResponse.getContentType() != null ? chainResponse.getContentType() : FileTypeEnum.TEXT.getFileType();
FileTypeEnum fileTypeEnum = FileTypeEnum.getFileTypeEnumByFileExtensionOrFileType(contentType);
String contentTypeHeader = fileTypeEnum.getContentType();
response.setHeader(HttpHeaderConsts.CONTENT_TYPE, contentTypeHeader);
String contentType = chainResponse.getContentType();
if (StringUtils.isBlank(contentType)) {
contentType = FileTypeEnum.TEXT.getContentType();
}
response.setHeader(HttpHeaderConsts.CONTENT_TYPE, contentType);
}

private void setResponseHeadForV2(HttpServletResponse response) {
Expand Down Expand Up @@ -238,12 +248,6 @@ private void writeContentForV2(HttpServletResponse response, ConfigQueryChainRes
}
}

private static String getDecryptContent(ConfigQueryChainResponse chainResponse, String dataId) {
Pair<String, String> pair = EncryptionHandler.decryptHandler(dataId, chainResponse.getEncryptedDataKey(),
chainResponse.getContent());
return pair.getSecond();
}

private String writeResponseForV1(HttpServletResponse response, Result<String> result) throws IOException {
PrintWriter writer = response.getWriter();
writer.println(result.getData());
Expand Down Expand Up @@ -282,20 +286,23 @@ private void logPullEvent(String dataId, String group, String tenant, String req
if (status == ConfigQueryChainResponse.ConfigQueryStatus.CONFIG_QUERY_CONFLICT) {
ConfigTraceService.logPullEvent(dataId, group, tenant, requestIpApp, -1, pullEvent,
ConfigTraceService.PULL_TYPE_CONFLICT, -1, clientIp, notify, "http");
} else if (status == ConfigQueryChainResponse.ConfigQueryStatus.CONFIG_NOT_FOUND || chainResponse.getContent() == null) {
} else if (status == ConfigQueryChainResponse.ConfigQueryStatus.CONFIG_NOT_FOUND
|| chainResponse.getContent() == null) {
ConfigTraceService.logPullEvent(dataId, group, tenant, requestIpApp, -1, pullEvent,
ConfigTraceService.PULL_TYPE_NOTFOUND, -1, clientIp, notify, "http");
} else {
long delayed = notify ? -1 : System.currentTimeMillis() - chainResponse.getLastModified();
ConfigTraceService.logPullEvent(dataId, group, tenant, requestIpApp, chainResponse.getLastModified(), pullEvent,
ConfigTraceService.PULL_TYPE_OK, delayed, clientIp, notify, "http");
ConfigTraceService.logPullEvent(dataId, group, tenant, requestIpApp, chainResponse.getLastModified(),
pullEvent, ConfigTraceService.PULL_TYPE_OK, delayed, clientIp, notify, "http");
}
}

private void setCommonResponseHead(HttpServletResponse response, ConfigQueryChainResponse chainResponse, String tag) {
String contentType = chainResponse.getContentType() != null ? chainResponse.getContentType() : FileTypeEnum.TEXT.getFileType();
private void setCommonResponseHead(HttpServletResponse response, ConfigQueryChainResponse chainResponse,
String tag) {
String configType = chainResponse.getConfigType() != null ? chainResponse.getConfigType()
: FileTypeEnum.TEXT.getFileType();

response.setHeader(CONFIG_TYPE, contentType);
response.setHeader(CONFIG_TYPE, configType);
response.setHeader(CONTENT_MD5, chainResponse.getMd5());
response.setHeader("Pragma", "no-cache");
response.setDateHeader("Expires", 0);
Expand All @@ -312,8 +319,9 @@ private void setCommonResponseHead(HttpServletResponse response, ConfigQueryChai
response.setHeader("isBeta", "true");
} else if (TagGrayRule.TYPE_TAG.equals(chainResponse.getMatchedGray().getGrayRule().getType())) {
try {
response.setHeader(TagGrayRule.TYPE_TAG, URLEncoder.encode(chainResponse.getMatchedGray().getGrayRule().getRawGrayRuleExp(),
StandardCharsets.UTF_8.displayName()));
response.setHeader(TagGrayRule.TYPE_TAG,
URLEncoder.encode(chainResponse.getMatchedGray().getGrayRule().getRawGrayRuleExp(),
StandardCharsets.UTF_8.displayName()));
} catch (Exception e) {
LOGGER.error("Error encoding tag", e);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ public ConfigQueryResponse handle(ConfigQueryRequest request, RequestMeta meta)
response.setMd5(chainResponse.getMd5());
response.setEncryptedDataKey(chainResponse.getEncryptedDataKey());
response.setContent(chainResponse.getContent());
response.setContentType(chainResponse.getConfigType());
response.setLastModified(chainResponse.getLastModified());

String pullType = ConfigTraceService.PULL_TYPE_OK;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package com.alibaba.nacos.config.server.service.query;

import com.alibaba.nacos.config.server.service.query.handler.ConfigChainEntryHandler;
import com.alibaba.nacos.config.server.service.query.handler.ConfigContentTypeHandler;
import com.alibaba.nacos.config.server.service.query.handler.FormalHandler;
import com.alibaba.nacos.config.server.service.query.handler.GrayRuleMatchHandler;
import com.alibaba.nacos.config.server.service.query.handler.SpecialTagNotFoundHandler;
Expand All @@ -32,6 +33,7 @@ public class DefaultConfigQueryHandlerChainBuilder implements ConfigQueryHandler
public ConfigQueryHandlerChain build() {
ConfigQueryHandlerChain chain = new ConfigQueryHandlerChain();
chain.addHandler(new ConfigChainEntryHandler())
.addHandler(new ConfigContentTypeHandler())
.addHandler(new GrayRuleMatchHandler())
.addHandler(new SpecialTagNotFoundHandler())
.addHandler(new FormalHandler());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,22 +17,23 @@
package com.alibaba.nacos.config.server.service.query.handler;

/**
* AbstractConfigQueryHandler.
* This abstract class provides a base implementation for configuration query handlers.
* It implements the {@link ConfigQueryHandler} interface and handles the chaining of handlers.
* AbstractConfigQueryHandler. This abstract class provides a base implementation for configuration query handlers. It
* implements the {@link ConfigQueryHandler} interface and handles the chaining of handlers.
*
* @author Nacos
*/
public abstract class AbstractConfigQueryHandler implements ConfigQueryHandler {

public ConfigQueryHandler nextHandler;

public void setNextHandler(ConfigQueryHandler nextHandler) {
this.nextHandler = nextHandler;
}

@Override
public ConfigQueryHandler getNextHandler() {
return this.nextHandler;
}

@Override
public void setNextHandler(ConfigQueryHandler nextHandler) {
this.nextHandler = nextHandler;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*
* Copyright 1999-2024 Alibaba Group Holding Ltd.
*
* 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.alibaba.nacos.config.server.service.query.handler;

import com.alibaba.nacos.config.server.enums.FileTypeEnum;
import com.alibaba.nacos.config.server.service.query.model.ConfigQueryChainRequest;
import com.alibaba.nacos.config.server.service.query.model.ConfigQueryChainResponse;

import java.io.IOException;

/**
* The type Config content type handler.
* @author Sunrisea
*/
public class ConfigContentTypeHandler extends AbstractConfigQueryHandler {

private static final String CONFIG_CONTENT_TYPE_HANDLER_NAME = "ConfigContentTypeHandler";

@Override
public String getName() {
return CONFIG_CONTENT_TYPE_HANDLER_NAME;
}

@Override
public ConfigQueryChainResponse handle(ConfigQueryChainRequest request) throws IOException {
ConfigQueryChainResponse response = getNextHandler().handle(request);
if (response.getStatus() == ConfigQueryChainResponse.ConfigQueryStatus.CONFIG_NOT_FOUND
|| response.getStatus() == ConfigQueryChainResponse.ConfigQueryStatus.SPECIAL_TAG_CONFIG_NOT_FOUND) {
return response;
}
String contentType =
response.getContentType() != null ? response.getContentType() : FileTypeEnum.TEXT.getFileType();
FileTypeEnum fileTypeEnum = FileTypeEnum.getFileTypeEnumByFileExtensionOrFileType(contentType);
String contentTypeHeader = fileTypeEnum.getContentType();
response.setContentType(contentTypeHeader);
return response;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

package com.alibaba.nacos.config.server.service.query.handler;

import com.alibaba.nacos.common.utils.StringUtils;
import com.alibaba.nacos.config.server.model.CacheItem;
import com.alibaba.nacos.config.server.service.dump.disk.ConfigDiskServiceFactory;
import com.alibaba.nacos.config.server.service.query.model.ConfigQueryChainRequest;
Expand All @@ -24,9 +25,9 @@
import java.io.IOException;

/**
* Formal Handler.
* This class represents a formal handler in the configuration query processing chain.
* If the request has not been processed by previous handlers, it will be handled by this handler.
* Formal Handler. This class represents a formal handler in the configuration query processing chain. If the request
* has not been processed by previous handlers, it will be handled by this handler.
*
* @author Nacos
*/
public class FormalHandler extends AbstractConfigQueryHandler {
Expand All @@ -48,16 +49,19 @@ public ConfigQueryChainResponse handle(ConfigQueryChainRequest request) throws I

CacheItem cacheItem = ConfigChainEntryHandler.getThreadLocalCacheItem();
String md5 = cacheItem.getConfigCache().getMd5();
String content = ConfigDiskServiceFactory.getInstance().getContent(dataId, group, tenant);
if (StringUtils.isBlank(content)) {
response.setStatus(ConfigQueryChainResponse.ConfigQueryStatus.CONFIG_NOT_FOUND);
return response;
}
long lastModified = cacheItem.getConfigCache().getLastModifiedTs();
String encryptedDataKey = cacheItem.getConfigCache().getEncryptedDataKey();
String contentType = cacheItem.getType();
String content = ConfigDiskServiceFactory.getInstance().getContent(dataId, group, tenant);

String configType = cacheItem.getType();
response.setContent(content);
response.setMd5(md5);
response.setLastModified(lastModified);
response.setEncryptedDataKey(encryptedDataKey);
response.setContentType(contentType);
response.setConfigType(configType);
response.setStatus(ConfigQueryChainResponse.ConfigQueryStatus.CONFIG_FOUND_FORMAL);

return response;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,8 @@
import java.io.IOException;

/**
* GrayRuleMatchHandler.
* This class represents a gray rule handler in the configuration query processing chain.
* It checks if the request matches any gray rules and processes the request accordingly.
* GrayRuleMatchHandler. This class represents a gray rule handler in the configuration query processing chain. It
* checks if the request matches any gray rules and processes the request accordingly.
*
* @author Nacos
*/
Expand Down Expand Up @@ -69,7 +68,7 @@ public ConfigQueryChainResponse handle(ConfigQueryChainRequest request) throws I
response.setLastModified(lastModified);
response.setEncryptedDataKey(encryptedDataKey);
response.setMatchedGray(matchedGray);
response.setContentType(cacheItem.getType());
response.setConfigType(cacheItem.getType());
response.setStatus(ConfigQueryChainResponse.ConfigQueryStatus.CONFIG_FOUND_GRAY);

return response;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,6 @@
package com.alibaba.nacos.config.server.service.query.handler;

import com.alibaba.nacos.common.utils.StringUtils;
import com.alibaba.nacos.config.server.model.CacheItem;
import com.alibaba.nacos.config.server.service.dump.disk.ConfigDiskServiceFactory;
import com.alibaba.nacos.config.server.service.query.model.ConfigQueryChainRequest;
import com.alibaba.nacos.config.server.service.query.model.ConfigQueryChainResponse;

Expand All @@ -43,25 +41,7 @@ public String getName() {
public ConfigQueryChainResponse handle(ConfigQueryChainRequest request) throws IOException {
if (StringUtils.isNotBlank(request.getTag())) {
ConfigQueryChainResponse response = new ConfigQueryChainResponse();

String dataId = request.getDataId();
String group = request.getGroup();
String tenant = request.getTenant();

CacheItem cacheItem = ConfigChainEntryHandler.getThreadLocalCacheItem();
String md5 = cacheItem.getConfigCache().getMd5();
long lastModified = cacheItem.getConfigCache().getLastModifiedTs();
String encryptedDataKey = cacheItem.getConfigCache().getEncryptedDataKey();
String contentType = cacheItem.getType();
String content = ConfigDiskServiceFactory.getInstance().getContent(dataId, group, tenant);

response.setContent(content);
response.setMd5(md5);
response.setLastModified(lastModified);
response.setEncryptedDataKey(encryptedDataKey);
response.setContentType(contentType);
response.setStatus(ConfigQueryChainResponse.ConfigQueryStatus.SPECIAL_TAG_CONFIG_NOT_FOUND);

return response;
} else {
return nextHandler.handle(request);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ public class ConfigQueryChainResponse {

private String contentType;

private String configType;

private String encryptedDataKey;

private String md5;
Expand Down Expand Up @@ -89,6 +91,14 @@ public void setContentType(String contentType) {
this.contentType = contentType;
}

public String getConfigType() {
return configType;
}

public void setConfigType(String configType) {
this.configType = configType;
}

public String getEncryptedDataKey() {
return encryptedDataKey;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,10 @@
import com.alibaba.nacos.config.server.model.gray.ConfigGrayPersistInfo;
import com.alibaba.nacos.config.server.model.gray.GrayRuleManager;
import com.alibaba.nacos.config.server.model.gray.TagGrayRule;
import com.alibaba.nacos.config.server.service.query.ConfigQueryChainService;
import com.alibaba.nacos.config.server.service.ConfigCacheService;
import com.alibaba.nacos.config.server.service.dump.disk.ConfigDiskServiceFactory;
import com.alibaba.nacos.config.server.service.dump.disk.ConfigRocksDbDiskService;
import com.alibaba.nacos.config.server.service.query.ConfigQueryChainService;
import com.alibaba.nacos.config.server.utils.GroupKey2;
import com.alibaba.nacos.config.server.utils.PropertyUtil;
import com.alibaba.nacos.sys.env.EnvUtil;
Expand Down Expand Up @@ -205,9 +205,9 @@ void testGetTagNotFound() throws Exception {

//check content&md5
assertNull(response.getContent());
assertEquals(MD5Utils.md5Hex(content, "UTF-8"), response.getMd5());
assertNull(response.getMd5());
assertEquals(CONFIG_NOT_FOUND, response.getErrorCode());
assertEquals("key_testGetTag_NotFound", response.getEncryptedDataKey());
assertNull(response.getEncryptedDataKey());

//check flags.
assertFalse(response.isBeta());
Expand Down
Loading

0 comments on commit 8a136c2

Please sign in to comment.