hash
为了实现效率,和list
一样,hash
在实现的时候也是分为meta
数据和field
数据,meta
数据实际上只有这个key下面的field
数量,field
数据就是存储自身的value信息。hash
不像list
那么复杂,每field
节点不存在顺序关系,每个field
都是独立存在,所以无论是在meta
还是field
存储的数据都是非常简单的。
数据格式
下面四个表格分别:
meta |
原始key字符串 |
H(1) |
key(var) |
meta |
key长度 |
key字符串 |
固定 |
field key字符串 |
h(1) |
key size(1) |
key(var) |
=(1) |
field key(var) |
举例
hset test field1 123
hset test field2 456
meta |
原始key字符串 |
H(1) |
key(var) |
H |
test |
meta |
key长度 |
key字符串 |
固定 |
field key字符串 |
h(1) |
key size(1) |
key(var) |
=(1) |
field key(var) |
h |
4 |
test |
= |
field1 |
h |
4 |
test |
= |
field2 |
value字符串 |
value(var) |
123 |
456 |
meta |
原始key字符串 |
H(1) |
key(var) |
inline std::string EncodeHsizeKey(const rocksdb::Slice &name) {
std::string buf;
buf.append(1, DataType::kHSize);
buf.append(name.data(), name.size());
return buf;
}
inline int DecodeHsizeKey(const rocksdb::Slice &slice, std::string *name) {
Decoder decoder(slice.data(), slice.size());
if (decoder.Skip(1) == -1) {
return -1;
}
if (decoder.ReadData(name) == -1) {
return -1;
}
return 0;
}
typedef DefaultMeta HashMeta;
struct DefaultMeta : public NemoMeta {
int64_t len;
DefaultMeta() : len(0) {}
explicit DefaultMeta(int64_t _len):len(_len) {}
virtual bool DecodeFrom(const std::string& raw_meta) {
if (raw_meta.size() != sizeof(uint64_t)) {
return false;
}
len = *(int64_t *)raw_meta.data();
return true;
}
virtual bool EncodeTo(std::string& raw_meta) {
raw_meta.clear();
raw_meta.append((char *)&len, sizeof(int64_t));
return true;
}
virtual std::string ToString() {
char buf[32];
std::string res("Len : ");
Int64ToStr(buf, 32, len);
res.append(buf);
return res;
}
};
Hash field key
meta |
key长度 |
key字符串 |
固定 |
field key字符串 |
h(1) |
key size(1) |
key(var) |
=(1) |
field key(var) |
inline std::string EncodeHashKey(const rocksdb::Slice &name, const rocksdb::Slice &key) {
std::string buf;
buf.append(1, DataType::kHash);
buf.append(1, (uint8_t)name.size());
buf.append(name.data(), name.size());
buf.append(1, '=');
buf.append(key.data(), key.size());
return buf;
}
inline int DecodeHashKey(const rocksdb::Slice &slice, std::string *name, std::string *key) {
Decoder decoder(slice.data(), slice.size());
if (decoder.Skip(1) == -1) {
return -1;
}
if (decoder.ReadLenData(name) == -1) {
return -1;
}
if (decoder.Skip(1) == -1) {
return -1;
}
if (decoder.ReadData(key) == -1) {
return -1;
}
return 0;
}
Hash field value
:
代码实现
HSet
- 功能:将哈希表key中的域field的值设为value。
- 实现:
- 获取行锁
DoHSet
具体处理,需要写入的kv,加到writebatch
中
- 首先用key和field编码出
hash field key
,获取这个key对应的值
- 如果找到,说明原来就存在这个field,相当于修改,返回值设置为0
- 如果没找到,说明原来这个filed是不存在的,相当于新增,返回值设置为0
- 将新的
hash field value
写入到对应的hash field key
中
- 判断返回值,如果是新增field,需要调用
IncrHLen
,修改hash meta value
- 用
key
编码出hash meta key
,先取出原来的值,在原来的基础上增加1,加入writebatch
- 调用
WriteWithOldKeyTTL
将writebatch
写入硬盘
int64_t Nemo::HLen(const std::string &key) {
std::string size_key = EncodeHsizeKey(key);
std::string val;
Status s;
s = hash_db_->Get(rocksdb::ReadOptions(), size_key, &val);
if (s.IsNotFound()) {
return 0;
} else if(!s.ok()) {
return -1;
} else {
if (val.size() != sizeof(uint64_t)) {
return 0;
}
int64_t ret = *(int64_t *)val.data();
return ret < 0? 0 : ret;
}
}
int Nemo::IncrHLen(const std::string &key, int64_t incr, rocksdb::WriteBatch &writebatch) {
int64_t len = HLen(key);
if (len == -1) {
return -1;
}
len += incr;
std::string size_key = EncodeHsizeKey(key);
writebatch.Put(size_key, rocksdb::Slice((char *)&len, sizeof(int64_t)));
return 0;
}
int Nemo::DoHSet(const std::string &key, const std::string &field, const std::string &val, rocksdb::WriteBatch &writebatch) {
int ret = 0;
std::string dbval;
Status s = HGet(key, field, &dbval);
if (s.IsNotFound()) { // not found
std::string hkey = EncodeHashKey(key, field);
writebatch.Put(hkey, val);
ret = 1;
} else {
if(dbval != val){
std::string hkey = EncodeHashKey(key, field);
writebatch.Put(hkey, val);
}
ret = 0;
}
return ret;
}
Status Nemo::HSet(const std::string &key, const std::string &field, const std::string &val) {
if (key.size() >= KEY_MAX_LENGTH || key.size() <= 0) {
return Status::InvalidArgument("Invalid key length");
}
Status s;
RecordLock l(&mutex_hash_record_, key);
rocksdb::WriteBatch writebatch;
int ret = DoHSet(key, field, val, writebatch);
if (ret > 0) {
if (IncrHLen(key, ret, writebatch) == -1) {
return Status::Corruption("incrhlen error");
}
}
s = hash_db_->WriteWithOldKeyTTL(rocksdb::WriteOptions(), &(writebatch));
return s;
}
HGet
- 功能:返回哈希表key中给定域field的值
- 实现:
- 用key和field编码出
hash field key
,调用Get
接口返回
Status Nemo::HGet(const std::string &key, const std::string &field, std::string *val) {
if (key.size() >= KEY_MAX_LENGTH || key.size() <= 0) {
return Status::InvalidArgument("Invalid key length");
}
std::string dbkey = EncodeHashKey(key, field);
Status s = hash_db_->Get(rocksdb::ReadOptions(), dbkey, val);
return s;
}
HDel
- 功能:删除哈希表key中的一个指定域,不存在的域将被忽略。
- 实现:
- 获取行锁
DoHDel
具体处理,需要写入的kv,加到writebatch
中
- 根据
key
和field
编码出hash field key
,获取hash field value
- 如果存在,则删除,返回值为1
- 如果不存在,返回值为0
- 判断是否删除了field
- 如果删除了,需要修改
hash meta value
int Nemo::DoHDel(const std::string &key, const std::string &field, rocksdb::WriteBatch &writebatch) {
int ret = 0;
std::string dbval;
Status s = HGet(key, field, &dbval);
if (s.ok()) {
std::string hkey = EncodeHashKey(key, field);
writebatch.Delete(hkey);
ret = 1;
} else if(s.IsNotFound()) {
ret = 0;
} else {
ret = -1;
}
return ret;
}
Status Nemo::HDel(const std::string &key, const std::string &field) {
if (key.size() >= KEY_MAX_LENGTH || key.size() <= 0) {
return Status::InvalidArgument("Invalid key length");
}
Status s;
RecordLock l(&mutex_hash_record_, key);
rocksdb::WriteBatch writebatch;
int ret = DoHDel(key, field, writebatch);
if (ret > 0) {
if (IncrHLen(key, -ret, writebatch) == -1) {
return Status::Corruption("incrlen error");
}
s = hash_db_->WriteWithKeyTTL(rocksdb::WriteOptions(), &(writebatch));
return s;
} else if (ret == 0) {
return Status::NotFound();
} else {
return Status::Corruption("DoHDel error");
}
}
HExists
- 功能:查看哈希表key中,给定域field是否存在。
- 实现:
- 用key和field编码出
hash field key
,调用Get
接口,判断返回值
bool Nemo::HExists(const std::string &key, const std::string &field) {
Status s;
std::string dbkey = EncodeHashKey(key, field);
std::string val;
s = hash_db_->Get(rocksdb::ReadOptions(), dbkey, &val);
if (s.ok()) {
return true;
} else {
return false;
}
}
HKeys
- 功能:返回哈希表key中的所有域。
- 实现:
TODO
HGetall
- 功能:返回哈希表key中,所有的域和值。
- 实现:
TODO
HLen
- 功能:返回哈希表 key 中域的数量。
- 实现:
TODO
HMSet
- 功能:同时将多个field-value(域-值)对设置到哈希表key中。
- 实现:
TODO
HMGet
- 功能:返回哈希表key中,一个或多个给定域的值。
- 实现:
TODO
HSetnx
- 功能:将哈希表key中的域field的值设置为value,当且仅当域field不存在。
- 实现:
TODO
HStrlen
- 功能:哈希表key中域field的value的长度
- 实现:
int64_t Nemo::HStrlen(const std::string &key, const std::string &field) {
Status s;
std::string val;
s = HGet(key, field, &val);
if (s.ok()) {
return val.length();
} else if (s.IsNotFound()) {
return 0;
} else {
return -1;
}
}
HVals
- 功能:返回哈希表key中所有域的值。
- 实现:
TODO
HIncrby
- 功能:为哈希表 key中的域field的值加上增量increment 。
- 实现:
TODO
HIncrbyfloat
- 功能:为哈希表key中的域field加上浮点数增量increment。
- 实现:
TODO