Skip to content

Commit

Permalink
support large file with namespace value length limit override
Browse files Browse the repository at this point in the history
  • Loading branch information
nobodyiam committed Nov 30, 2016
1 parent fc4f3e8 commit 0a6267d
Showing 1 changed file with 92 additions and 10 deletions.
@@ -1,23 +1,40 @@
package com.ctrip.framework.apollo.biz.service;

import com.google.common.base.Strings;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;

import com.ctrip.framework.apollo.biz.entity.Audit;
import com.ctrip.framework.apollo.biz.entity.Item;
import com.ctrip.framework.apollo.biz.entity.Namespace;
import com.ctrip.framework.apollo.biz.repository.ItemRepository;
import com.ctrip.framework.apollo.common.utils.BeanUtils;
import com.ctrip.framework.apollo.common.exception.BadRequestException;
import com.ctrip.framework.apollo.common.exception.NotFoundException;
import com.ctrip.framework.apollo.core.utils.ApolloThreadFactory;
import com.ctrip.framework.apollo.core.utils.StringUtils;
import com.dianping.cat.Cat;
import com.dianping.cat.message.Message;
import com.dianping.cat.message.Transaction;

import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.lang.reflect.Type;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;

@Service
public class ItemService {
public class ItemService implements InitializingBean {
private static final int DEFAULT_LIMIT_UPDATE_INTERVAL_IN_SECONDS = 60;

@Autowired
private ItemRepository itemRepository;
Expand All @@ -31,6 +48,61 @@ public class ItemService {
@Autowired
private ServerConfigService serverConfigService;

private AtomicInteger globalKeyLengthLimit;

private AtomicInteger globalValueLengthLimit;

private AtomicReference<Map<Long, Integer>> namespaceValueLengthOverride;

private Gson gson;

private ScheduledExecutorService executorService;

private static final Type namespaceValueLengthOverrideTypeReference =
new TypeToken<Map<Long, Integer>>() {
}.getType();

public ItemService() {
gson = new Gson();
globalKeyLengthLimit = new AtomicInteger(128);
globalValueLengthLimit = new AtomicInteger(20000);
namespaceValueLengthOverride = new AtomicReference<>();
executorService = Executors.newScheduledThreadPool(1, ApolloThreadFactory
.create("ItemServiceLimitUpdater", true));
}

@Override
public void afterPropertiesSet() throws Exception {
executorService.scheduleWithFixedDelay(() -> {
Transaction transaction = Cat.newTransaction("Apollo.ItemServiceLimitUpdater", "updateLimit");
try {
updateLimits();
transaction.setStatus(Message.SUCCESS);
} catch (Throwable ex) {
transaction.setStatus(ex);
} finally {
transaction.complete();
}
}, 0, getLimitUpdateIntervalInSeconds(), TimeUnit.SECONDS);
}

private void updateLimits() {
String keyLengthLimit = serverConfigService.getValue("item.key.length.limit", null);
if (!Strings.isNullOrEmpty(keyLengthLimit)) {
globalKeyLengthLimit.set(Integer.valueOf(keyLengthLimit));
}
String valueLengthLimit = serverConfigService.getValue("item.value.length.limit", null);
if (!Strings.isNullOrEmpty(valueLengthLimit)) {
globalValueLengthLimit.set(Integer.valueOf(valueLengthLimit));
}
String namespaceValueLengthOverrideString =
serverConfigService.getValue("namespace.value.length.limit.override", null);
if (!Strings.isNullOrEmpty(namespaceValueLengthOverrideString)) {
namespaceValueLengthOverride.set(gson.fromJson(
namespaceValueLengthOverrideString, namespaceValueLengthOverrideTypeReference));
}
}

@Transactional
public Item delete(long id, String operator) {
Item item = itemRepository.findOne(id);
Expand Down Expand Up @@ -100,7 +172,7 @@ public List<Item> findItems(String appId, String clusterName, String namespaceNa
@Transactional
public Item save(Item entity) {
checkItemKeyLength(entity.getKey());
checkItemValueLength(entity.getValue());
checkItemValueLength(entity.getNamespaceId(), entity.getValue());

entity.setId(0);//protection

Expand All @@ -120,7 +192,7 @@ public Item save(Item entity) {

@Transactional
public Item update(Item item) {
checkItemValueLength(item.getValue());
checkItemValueLength(item.getNamespaceId(), item.getValue());
Item managedItem = itemRepository.findOne(item.getId());
BeanUtils.copyEntityProperties(item, managedItem);
managedItem = itemRepository.save(managedItem);
Expand All @@ -131,20 +203,30 @@ public Item update(Item item) {
return managedItem;
}

private boolean checkItemValueLength(String value) {
int lengthLimit = Integer.valueOf(serverConfigService.getValue("item.value.length.limit", "20000"));
if (!StringUtils.isEmpty(value) && value.length() > lengthLimit) {
throw new BadRequestException("value too long. length limit:" + lengthLimit);
private boolean checkItemValueLength(long namespaceId, String value) {
int limit = getItemValueLengthLimit(namespaceId);
if (!StringUtils.isEmpty(value) && value.length() > limit) {
throw new BadRequestException("value too long. length limit:" + limit);
}
return true;
}

private boolean checkItemKeyLength(String key) {
int lengthLimit = Integer.valueOf(serverConfigService.getValue("item.key.length.limit", "128"));
if (!StringUtils.isEmpty(key) && key.length() > lengthLimit) {
throw new BadRequestException("key too long. length limit:" + lengthLimit);
if (!StringUtils.isEmpty(key) && key.length() > globalKeyLengthLimit.get()) {
throw new BadRequestException("key too long. length limit:" + globalKeyLengthLimit.get());
}
return true;
}

private int getItemValueLengthLimit(long namespaceId) {
if (namespaceValueLengthOverride.get() != null && namespaceValueLengthOverride.get()
.containsKey(namespaceId)) {
return namespaceValueLengthOverride.get().get(namespaceId);
}
return globalValueLengthLimit.get();
}

private int getLimitUpdateIntervalInSeconds() {
return DEFAULT_LIMIT_UPDATE_INTERVAL_IN_SECONDS;
}
}

0 comments on commit 0a6267d

Please sign in to comment.