perf[orm]: 去掉IEntityCaches多余的接口

This commit is contained in:
jaysunxiao
2021-10-19 17:28:30 +08:00
parent 4c3bb625fc
commit 5d656f24c6
5 changed files with 42 additions and 46 deletions
@@ -63,13 +63,18 @@ import java.util.stream.Collectors;
*/
public class OrmManager implements IOrmManager {
private static final Map<Class<? extends IEntity<?>>, IEntityCaches<?, ?>> entityCachesMap = new HashMap<>();
private OrmConfig ormConfig;
private MongoClient mongoClient;
private MongoDatabase mongodbDatabase;
/**
* 全部的Entity定义,key为对应的classvalue为当前的Entity是否在当前项目中以缓存的形式使用
*/
private final Map<Class<?>, Boolean> allEntityCachesUsableMap = new HashMap<>();
private final Map<Class<? extends IEntity<?>>, IEntityCaches<?, ?>> entityCachesMap = new HashMap<>();
private final Map<Class<? extends IEntity<?>>, String> collectionNameMap = new ConcurrentHashMap<>();
public OrmConfig getOrmConfig() {
@@ -87,6 +92,7 @@ public class OrmManager implements IOrmManager {
for (var entityDef : entityDefMap.values()) {
var entityCaches = new EntityCaches(entityDef);
entityCachesMap.put(entityDef.getClazz(), entityCaches);
allEntityCachesUsableMap.put(entityDef.getClazz(), false);
}
CodecRegistry pojoCodecRegistry = CodecRegistries.fromRegistries(
@@ -172,6 +178,7 @@ public class OrmManager implements IOrmManager {
public void inject() {
var applicationContext = OrmContext.getApplicationContext();
var beanNames = applicationContext.getBeanDefinitionNames();
for (var beanName : beanNames) {
var bean = applicationContext.getBean(beanName);
@@ -185,34 +192,37 @@ public class OrmManager implements IOrmManager {
}
Type[] types = ((ParameterizedType) type).getActualTypeArguments();
Class<? extends IEntity<?>> clazz = (Class<? extends IEntity<?>>) types[1];
IEntityCaches<?, ?> entityCaches = OrmContext.getOrmManager().getEntityCaches(clazz);
Class<? extends IEntity<?>> entityClazz = (Class<? extends IEntity<?>>) types[1];
IEntityCaches<?, ?> entityCaches = entityCachesMap.get(entityClazz);
if (entityCaches == null) {
throw new RuntimeException(StringUtils.format("实体缓存对象[entityCaches:{}]不存在", clazz));
throw new RuntimeException(StringUtils.format("实体缓存对象[entityCaches:{}]不存在", entityClazz));
}
ReflectionUtils.makeAccessible(field);
ReflectionUtils.setField(field, bean, entityCaches);
entityCaches.setUsable(true);
allEntityCachesUsableMap.put(entityClazz, true);
});
}
}
@Override
public void initAfter() {
var unusableEntityClassList = entityCachesMap.entrySet().stream()
.filter(it -> !it.getValue().isUsable())
allEntityCachesUsableMap.entrySet().stream()
.filter(it -> !it.getValue())
.map(it -> it.getKey())
.collect(Collectors.toList());
unusableEntityClassList.forEach(it -> {
entityCachesMap.remove(it);
});
.forEach(it -> entityCachesMap.remove(it));
}
@Override
public <E extends IEntity<?>> IEntityCaches<?, E> getEntityCaches(Class<E> clazz) {
var usable = allEntityCachesUsableMap.get(clazz);
if (usable == null) {
throw new RunException("没有定义[]的EntityCaches,无法获取", clazz.getCanonicalName());
}
if (!usable) {
throw new RunException("Orm没有使用[]的EntityCaches,为了节省内存提前释放了它;只有使用EntityCachesInjection注解的Entity才能被动态获取", clazz.getCanonicalName());
}
return (IEntityCaches<?, E>) entityCachesMap.get(clazz);
}
@@ -233,7 +243,6 @@ public class OrmManager implements IOrmManager {
collectionName = StringUtils.substringBeforeLast(StringUtils.uncapitalize(entityClazz.getSimpleName()), "Entity");
collectionNameMap.put(entityClazz, collectionName);
}
return mongodbDatabase.getCollection(collectionName, entityClazz);
}
@@ -50,11 +50,9 @@ public class EntityCaches<PK extends Comparable<PK>, E extends IEntity<PK>> impl
private static final int BATCH_SIZE = 512;
private EntityDef entityDef;
private final EntityDef entityDef;
private LoadingCache<PK, PNode<E>> cache;
private boolean usable;
private final LoadingCache<PK, PNode<E>> cache;
public EntityCaches(EntityDef entityDef) {
this.entityDef = entityDef;
@@ -304,16 +302,6 @@ public class EntityCaches<PK extends Comparable<PK>, E extends IEntity<PK>> impl
return cache.estimatedSize();
}
@Override
public boolean isUsable() {
return this.usable;
}
@Override
public void setUsable(boolean usable) {
this.usable = usable;
}
@Override
public String recordStatus() {
var stats = cache.stats();
@@ -55,10 +55,6 @@ public interface IEntityCaches<PK extends Comparable<PK>, E extends IEntity<PK>>
long size();
boolean isUsable();
void setUsable(boolean usable);
/**
* 统计缓存命中率
*/
@@ -28,11 +28,11 @@ public interface IEntity<PK extends Comparable<PK>> {
/**
* 一个文档的写入到数据库的version版本,version的get和set方法
* <p>
* 写入一条数据到数据库的时候会对比以下老的vs和数据库的vs是不是一样,不是一样的话无法写入,一致的话就写入数据并且让vs自增+1.
* 主要是为了防止多个服务器去操作同一条数据,保证分布式环境的数据一致性就是一个数据版本号的简单实现,版本号一致才能写入数据。
* 在分布式环境的那种有状态服务器中会遇到,比如网关路由一个玩家的数据到a服务器,这个时候你加了一个b服务器,有可能下一条数据就被路由到b。
* 写入一条数据到数据库的时候会对比当前entity的vs和数据库的vs是不是一样,不是一样的话无法写入,一致的话就写入数据并且让vs自增+1.
* 主要是为了防止多个服务器去操作同一条数据,保证分布式环境的数据一致性;简单的说就是一个数据版本号的简单实现,版本号一致才能写入数据。
* 在分布式环境中,会存在有状态服务器,比如网关路由一个玩家的数据到a服务器,这个时候你加了一个b服务器,有可能下一条数据就被路由到b。
* 虽然用了一致性hash的负载均衡算法,但是一样有概率会让某些消息路由到不同服务器。
* 这个时候版本号就可以保只有一台服务器可以对数据库做操作,不用担心多个服务器去操作数据。
* 这个时候版本号就可以保只有一台服务器可以对数据库做操作,不用担心多个服务器去操作数据。
* 这是一个容错的操作,真实环境下很少发生。为了高性能必须要把服务器做成有状态的,这个容错操作就是最后一道保证数据一致的方案。
* mongodb更新的时候是原子的,并发更新同一条数据只有一条数据会写入,第二条数据写入的时候版本号已经不一致了,所以老版本号的数据无法写入。
* 写入的时候只要发现版本号不一致,就让缓存失效,重新读取数据库最新的数据。
@@ -15,6 +15,7 @@ package com.zfoo.storage.manager;
import com.zfoo.protocol.collection.CollectionUtils;
import com.zfoo.protocol.exception.ExceptionUtils;
import com.zfoo.protocol.exception.RunException;
import com.zfoo.protocol.util.ReflectionUtils;
import com.zfoo.protocol.util.StringUtils;
import com.zfoo.storage.StorageContext;
@@ -34,7 +35,6 @@ import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.*;
import java.util.stream.Collectors;
/**
* @author jaysunxiao
@@ -56,12 +56,12 @@ public class StorageManager implements IStorageManager {
/**
* 在当前项目被依赖注入,被使用的Storage
*/
private Map<Class<?>, Storage<?, ?>> storageMap = new HashMap<>();
private final Map<Class<?>, Storage<?, ?>> storageMap = new HashMap<>();
/**
* 全部的Storage定义,key为对应的excel配置表,value为当前配置表是否在当前项目中使用
*/
private Map<Class<?>, Boolean> allStorageUsableMap = new HashMap<>();
private final Map<Class<?>, Boolean> allStorageUsableMap = new HashMap<>();
public StorageConfig getStorageConfig() {
return storageConfig;
@@ -133,7 +133,7 @@ public class StorageManager implements IStorageManager {
Class<?> resourceClazz = (Class<?>) types[1];
Storage<?, ?> storage = StorageContext.getStorageManager().getStorage(resourceClazz);
Storage<?, ?> storage = storageMap.get(resourceClazz);
if (storage == null) {
throw new RuntimeException(StringUtils.format("静态类资源[resource:{}]不存在", resourceClazz.getSimpleName()));
@@ -158,18 +158,21 @@ public class StorageManager implements IStorageManager {
@Override
public void initAfter() {
var unusableStorageClassList = allStorageUsableMap.entrySet().stream()
allStorageUsableMap.entrySet().stream()
.filter(it -> !it.getValue())
.map(it -> it.getKey())
.collect(Collectors.toList());
unusableStorageClassList.forEach(it -> {
storageMap.remove(it);
});
.forEach(it -> storageMap.remove(it));
}
@Override
public Storage<?, ?> getStorage(Class<?> clazz) {
var usable = allStorageUsableMap.get(clazz);
if (usable == null) {
throw new RunException("没有定义[{}]的Storage,无法获取", clazz.getCanonicalName());
}
if (!usable) {
throw new RunException("Storage没有使用[{}],为了节省内存提前释放了它;只有使用ResInjection注解的Storage才能被动态获取", clazz.getCanonicalName());
}
return storageMap.get(clazz);
}