摘要
本节讲解顺序如下
KVConfigManager作用
字段
lock 读写锁
configTable 内存记录的配置
方法
构造函数
load:加载配置文件,读取到内存的configTable中
putKVConfig:添加一条记录
deleteKVConfig:删除一条记录
persist:将内存记录的configTable持久化到配置文件
getKVListByNamespace:拿到configTable对应namespace的所有记录
getKVConfig:获取configTable中namespace,key对应的一条记录
printAllPeriodically:打印configTable所有配置,被周期性的调用
思考
refer
说明
KVConfigManager作用是
加载namesrvController指定的kvConfig配置文件(常为xxx/kvConfig.json)到内存
读取或增加,删除kvConfig记录
将内存记录的配置,持久化到文件
打印所有kvConfig配置
字段
private static final Logger log = LoggerFactory.getLogger(LoggerName.NAMESRV_LOGGER_NAME);
private final NamesrvController namesrvController;//NameServer控制类
private final ReadWriteLock lock = new ReentrantReadWriteLock();//读写锁
private final HashMap > configTable =
new HashMap>();
主要注意
lock 是一个读写锁,用来控制并发
configTable 就是在内存中记录住的kv配置,第一级key为NameSpace(暂时什么用还不清楚)
方法
构造函数
public KVConfigManager(NamesrvController namesrvController) {
this.namesrvController = namesrvController;
}
传入一个NamesrvController,目的是为了后面获取到kvConfig的配置路径
load
加载配置文件,读取到内存的configTable中
源码如下
public void load() {
String content = null;
try {
//解析kvConfigPath,默认为NamesrvConfig.kvConfigPath(../kvConfig.json),解析文件,得到内容,赋给content
content = MixAll.file2String(this.namesrvController.getNamesrvConfig().getKvConfigPath());
} catch (IOException e) {
log.warn("Load KV config table exception", e);
}
if (content != null) {
KVConfigSerializeWrapper kvConfigSerializeWrapper =
KVConfigSerializeWrapper.fromJson(content, KVConfigSerializeWrapper.class);//根据json的文本内容解析得到KVConfigSerializeWrapper对象
if (null != kvConfigSerializeWrapper) {
this.configTable.putAll(kvConfigSerializeWrapper.getConfigTable());//存入configTable
log.info("load KV config table OK");
}
}
}
步骤就是
根据kvConfigPath得到文件内容
以json格式解析得到KVConfigSerializeWrapper对象
放入configTable属性中
putKVConfig
添加一条记录
源码如下
public void putKVConfig(final String namespace, final String key, final String value) {
try {
this.lock.writeLock().lockInterruptibly();
try {
HashMap kvTable = this.configTable.get(namespace);
if (null == kvTable) {
kvTable = new HashMap();
this.configTable.put(namespace, kvTable);
log.info("putKVConfig create new Namespace {}", namespace);
}
final String prev = kvTable.put(key, value);
if (null != prev) {//有旧的key,更新
log.info("putKVConfig update config item, Namespace: {} Key: {} Value: {}",
namespace, key, value);
} else {//没有,创建新的
log.info("putKVConfig create new config item, Namespace: {} Key: {} Value: {}",
namespace, key, value);
}
} finally {
this.lock.writeLock().unlock();
}
} catch (InterruptedException e) {
log.error("putKVConfig InterruptedException", e);
}
this.persist();//持久化到文件
}
步骤就是
放入configTable中,namespace对应一级key,key对应二级
然后将configTable进行持久化到文件
deleteKVConfig
删除一条记录
源码如下
public void deleteKVConfig(final String namespace, final String key) {
try {
this.lock.writeLock().lockInterruptibly();
try {
HashMap kvTable = this.configTable.get(namespace);
if (null != kvTable) {
String value = kvTable.remove(key);
log.info("deleteKVConfig delete a config item, Namespace: {} Key: {} Value: {}",
namespace, key, value);
}
} finally {
this.lock.writeLock().unlock();
}
} catch (InterruptedException e) {
log.error("deleteKVConfig InterruptedException", e);
}
this.persist();//持久化到文件
}
步骤就是
从configTable删除对应记录
然后将configTable持久化到文件
persist
将内存记录的configTable持久化到配置文件
源码如下
public void persist() {
try {
this.lock.readLock().lockInterruptibly();
try {
//把configTable放入KVConfigSerializeWrapper
KVConfigSerializeWrapper kvConfigSerializeWrapper = new KVConfigSerializeWrapper();
kvConfigSerializeWrapper.setConfigTable(this.configTable);
//把KVConfigSerializeWrapper转成json串
String content = kvConfigSerializeWrapper.toJson();
if (null != content) {
//把内容写入 kvConfig的文件
MixAll.string2File(content, this.namesrvController.getNamesrvConfig().getKvConfigPath());
}
} catch (IOException e) {
log.error("persist kvconfig Exception, "
+ this.namesrvController.getNamesrvConfig().getKvConfigPath(), e);
} finally {
this.lock.readLock().unlock();
}
} catch (InterruptedException e) {
log.error("persist InterruptedException", e);
}
}
步骤就是
1.把configTable放入KVConfigSerializeWrapper
2.把KVConfigSerializeWrapper转成json串
3.把json串写入kvConfig文件
getKVListByNamespace
拿到configTable对应namespace的所有记录
源码如下
/**
* 拿到configTable对应namespace的所有记录,
* 返回encode得到的byte[]
*/
public byte[] getKVListByNamespace(final String namespace) {
try {
this.lock.readLock().lockInterruptibly();
try {
HashMap kvTable = this.configTable.get(namespace);
if (null != kvTable) {
KVTable table = new KVTable();
table.setTable(kvTable);
return table.encode();
}
} finally {
this.lock.readLock().unlock();
}
} catch (InterruptedException e) {
log.error("getKVListByNamespace InterruptedException", e);
}
return null;
}
getKVConfig
获取configTable中namespace,key对应的一条记录
源码如下
public String getKVConfig(final String namespace, final String key) {
try {
this.lock.readLock().lockInterruptibly();
try {
HashMap kvTable = this.configTable.get(namespace);
if (null != kvTable) {
return kvTable.get(key);
}
} finally {
this.lock.readLock().unlock();
}
} catch (InterruptedException e) {
log.error("getKVConfig InterruptedException", e);
}
return null;
}
printAllPeriodically
打印configTable所有配置,被周期性的调用
源码如下
public void printAllPeriodically() {
try {
this.lock.readLock().lockInterruptibly();
try {
log.info("--------------------------------------------------------");
{
log.info("configTable SIZE: {}", this.configTable.size());
Iterator>> it =
this.configTable.entrySet().iterator();
while (it.hasNext()) {//一级key
Entry> next = it.next();
Iterator> itSub = next.getValue().entrySet().iterator();
while (itSub.hasNext()) {//二级key
Entry nextSub = itSub.next();
log.info("configTable NS: {} Key: {} Value: {}", next.getKey(), nextSub.getKey(),
nextSub.getValue());
}
}
}
} finally {
this.lock.readLock().unlock();
}
} catch (InterruptedException e) {
log.error("printAllPeriodically InterruptedException", e);
}
}
思考
注意lock的使用
在各方法中适宜的调用读锁和写锁
问题
NameSpace有什么用?
只知道是一个区分的一级key