摘要
本節(jié)講解順序如下
KVConfigManager作用
字段
lock 讀寫鎖
configTable 內(nèi)存記錄的配置
方法
構(gòu)造函數(shù)
load:加載配置文件,讀取到內(nèi)存的configTable中
putKVConfig:添加一條記錄
deleteKVConfig:刪除一條記錄
persist:將內(nèi)存記錄的configTable持久化到配置文件
getKVListByNamespace:拿到configTable對(duì)應(yīng)namespace的所有記錄
getKVConfig:獲取configTable中namespace,key對(duì)應(yīng)的一條記錄
printAllPeriodically:打印configTable所有配置,被周期性的調(diào)用
思考
refer
說(shuō)明
KVConfigManager作用是
加載namesrvController指定的kvConfig配置文件(常為xxx/kvConfig.json)到內(nèi)存
讀取或增加,刪除kvConfig記錄
將內(nèi)存記錄的配置,持久化到文件
打印所有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<String/* Namespace */, HashMap<String/* Key */, String/* Value */>> configTable =
new HashMap<String, HashMap<String, String>>();
主要注意
lock 是一個(gè)讀寫鎖,用來(lái)控制并發(fā)
configTable 就是在內(nèi)存中記錄住的kv配置,第一級(jí)key為NameSpace(暫時(shí)什么用還不清楚)
方法
構(gòu)造函數(shù)
public KVConfigManager(NamesrvController namesrvController) {
this.namesrvController = namesrvController;
}
傳入一個(gè)NamesrvController,目的是為了后面獲取到kvConfig的配置路徑
load
加載配置文件,讀取到內(nèi)存的configTable中
源碼如下
public void load() {
String content = null;
try {
//解析kvConfigPath,默認(rèn)為NamesrvConfig.kvConfigPath(../kvConfig.json),解析文件,得到內(nèi)容,賦給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);//根據(jù)json的文本內(nèi)容解析得到KVConfigSerializeWrapper對(duì)象
if (null != kvConfigSerializeWrapper) {
this.configTable.putAll(kvConfigSerializeWrapper.getConfigTable());//存入configTable
log.info("load KV config table OK");
}
}
}
步驟就是
根據(jù)kvConfigPath得到文件內(nèi)容
以json格式解析得到KVConfigSerializeWrapper對(duì)象
放入configTable屬性中
putKVConfig
添加一條記錄
源碼如下
public void putKVConfig(final String namespace, final String key, final String value) {
try {
this.lock.writeLock().lockInterruptibly();
try {
HashMap<String, String> kvTable = this.configTable.get(namespace);
if (null == kvTable) {
kvTable = new HashMap<String, String>();
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 {//沒(méi)有,創(chuàng)建新的
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對(duì)應(yīng)一級(jí)key,key對(duì)應(yīng)二級(jí)
然后將configTable進(jìn)行持久化到文件
deleteKVConfig
刪除一條記錄
源碼如下
public void deleteKVConfig(final String namespace, final String key) {
try {
this.lock.writeLock().lockInterruptibly();
try {
HashMap<String, String> 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刪除對(duì)應(yīng)記錄
然后將configTable持久化到文件
persist
將內(nèi)存記錄的configTable持久化到配置文件
源碼如下
public void persist() {
try {
this.lock.readLock().lockInterruptibly();
try {
//把configTable放入KVConfigSerializeWrapper
KVConfigSerializeWrapper kvConfigSerializeWrapper = new KVConfigSerializeWrapper();
kvConfigSerializeWrapper.setConfigTable(this.configTable);
//把KVConfigSerializeWrapper轉(zhuǎn)成json串
String content = kvConfigSerializeWrapper.toJson();
if (null != content) {
//把內(nèi)容寫入 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轉(zhuǎn)成json串
3.把json串寫入kvConfig文件
getKVListByNamespace
拿到configTable對(duì)應(yīng)namespace的所有記錄
源碼如下
/**
* 拿到configTable對(duì)應(yīng)namespace的所有記錄,
* 返回encode得到的byte[]
*/
public byte[] getKVListByNamespace(final String namespace) {
try {
this.lock.readLock().lockInterruptibly();
try {
HashMap<String, String> 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對(duì)應(yīng)的一條記錄
源碼如下
public String getKVConfig(final String namespace, final String key) {
try {
this.lock.readLock().lockInterruptibly();
try {
HashMap<String, String> 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所有配置,被周期性的調(diào)用
源碼如下
public void printAllPeriodically() {
try {
this.lock.readLock().lockInterruptibly();
try {
log.info("--------------------------------------------------------");
{
log.info("configTable SIZE: {}", this.configTable.size());
Iterator<Entry<String, HashMap<String, String>>> it =
this.configTable.entrySet().iterator();
while (it.hasNext()) {//一級(jí)key
Entry<String, HashMap<String, String>> next = it.next();
Iterator<Entry<String, String>> itSub = next.getValue().entrySet().iterator();
while (itSub.hasNext()) {//二級(jí)key
Entry<String, String> 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的使用
在各方法中適宜的調(diào)用讀鎖和寫鎖
問(wèn)題
NameSpace有什么用?
只知道是一個(gè)區(qū)分的一級(jí)key