bool session::set(const char* name, const void* value, size_t len, bool delay /* = false */) { if (delay) { std::map<string, VBUF*>::iterator it = attrs_cache_.find(name); if (it == attrs_cache_.end()) attrs_cache_[name] = vbuf_new(value, len, TODO_SET); else attrs_cache_[name] = vbuf_set(it->second, value, len, TODO_SET); dirty_ = true; return true; } // 直接操作后端 cache 服务器,设置(添加/修改) 属性字段 string buf(256); // 调用纯虚接口,获得原来的 sid 数据 if (get_data(sid_->buf, buf) == false) { // 如果没有则创建新的 sid 数据 serialize(name, value, len, buf); } // 如果存在对应 sid 的数据,则将新数据添加在原来数据中 else { if (!sid_saved_) sid_saved_ = true; // 反序列化 deserialize(buf, attrs_); // 如果该属性已存在,则需要先释放原来的属性值后再添加新值 std::map<string, VBUF*>::iterator it = attrs_.find(name); if (it == attrs_.end()) attrs_[name] = vbuf_new(value, len, TODO_SET); else attrs_[name] = vbuf_set(it->second, value, len, TODO_SET); serialize(attrs_, buf); // 序列化数据 attrs_clear(attrs_); } // 调用纯虚接口,向 memcached 或类似缓存中添加数据 if (set_data(sid_->buf, buf.c_str(), buf.length(), ttl_) == false) { logger_error("set cache error, sid(%s)", sid_->buf); return false; } if (!sid_saved_) sid_saved_ = true; return true; }
void session::deserialize(string& buf, std::map<string, VBUF*>& attrs) { attrs_clear(attrs); // 先重置 session 前一次查询状态 ACL_ARGV* tokens = acl_argv_split(buf.c_str(), "\t"); ACL_ITER iter; acl_foreach(iter, tokens) { char* ptr = (char*) iter.data; // 重复使用原来的内存区,因为 tokens 中已经存储了中间结果数据 buf.clear(); if (unescape(ptr, strlen(ptr), buf) == false) { logger_error("unescape error"); continue; } ptr = buf.c_str(); // 因为 acl::string 肯定能保证缓冲区数据的尾部有 \0,所以在用 // strchr 时不必须担心越界问题,但 std::string 并不保证这样 char* p1 = strchr(ptr, 1); if (p1 == NULL || *(p1 + 1) == 0) continue; *p1++ = 0; std::map<string, VBUF*>::iterator it = attrs.find(ptr); // xxx: 以防有重复的属性 if (it != attrs.end()) vbuf_free(it->second); // 将从后端取得数据属性都设为 TODO_SET attrs[ptr] = vbuf_new(p1, buf.length() - (p1 - buf.c_str()), TODO_SET); }
session::session(time_t ttl /* = 0 */, const char* sid /* = NULL */) : ttl_(ttl) , dirty_(false) { struct timeval tv; (void) gettimeofday(&tv, NULL); if (sid == NULL || *sid == 0) { char buf[128]; snprintf(buf, sizeof(buf), "acl.%d.%d.%d", (int) tv.tv_sec, (int) tv.tv_usec, rand()); sid_ = vbuf_new(buf, strlen(buf), TODO_NUL); sid_saved_ = false; } else { sid_ = vbuf_new(sid, strlen(sid), TODO_NUL); sid_saved_ = true; } }
bool session::del(const char* name, bool delay /* = false */) { if (delay) { std::map<string, VBUF*>::iterator it = attrs_cache_.find(name); if (it == attrs_cache_.end()) attrs_cache_[name] = vbuf_new("", 0, TODO_DEL); else it->second->todo = TODO_DEL; dirty_ = true; return true; } // 直接操作后端 cache 服务器,删除属性字段 string buf(256); if (get_data(sid_->buf, buf) == false) return true; deserialize(buf, attrs_); std::map<string, VBUF*>::iterator it = attrs_.find(name); if (it == attrs_.end()) return false; // 先删除并释放对应的对象 vbuf_free(it->second); attrs_.erase(it); // 如果 sid 中已经没有了数据,则应该将 sid 对象从 memcached 中删除 if (attrs_.empty()) { // 调用虚函数,删除该 sid 对应的缓存内容 if (del_data(sid_->buf) == false) { logger_error("del sid(%s) error", sid_->buf); return false; } return true; } // 向 memcached 中重新添加剩余的数据 serialize(attrs_, buf); attrs_clear(attrs_); if (set_data(sid_->buf, buf.c_str(), buf.length(), ttl_) == false) { logger_error("set cache error, sid(%s)", sid_->buf); return false; } return true; }
// TODO add API unit tests int main() { int i, r; const int szbuf = 40, szfrag = szbuf / 4 * 3; const char src[szbuf *2] = "hello, world"; const char *fragstring = "1234567890ABCDEFGHIJabcdefhijk"; const char *s; char dest[szbuf*2] = ""; VBUF vbuf, *v = &vbuf; vbuf_new(v, szbuf); // check basic structure assert(v->buf && v->capacity == szbuf -1); assert(v->head == v->tail && v->tail == v->buf); assert(v->buf_end == v->buf + v->capacity + 1); // fragmentize it! vbuf_dbg_fragmentize(v); assert(vbuf_is_empty(v) && !vbuf_is_full(v)); vbuf_putblk(v, src, szfrag); // check macro API assert(!vbuf_is_empty(v)); assert(!vbuf_is_full(v)); assert(vbuf_capacity(v) == szbuf-1); assert(vbuf_size(v) == szfrag); assert(vbuf_space(v) == vbuf_capacity(v) - szfrag); assert(vbuf_peek(v) == src[0]); // try filling buffer with putblk/getblk vbuf_dbg_fragmentize(v); for (i = 0; i < 10; i++) { r = vbuf_putblk(v, src, szbuf / 10); vbuf_dbg_rpt(v); assert( i == 9 ? !r : r); assert(!vbuf_is_full(v)); } r = vbuf_putblk(v, src, vbuf_capacity(v) - vbuf_size(v)); assert(r && vbuf_is_full(v) && !vbuf_is_empty(v)); for (i = 0; i < 10; i++) { r = vbuf_getblk(v, dest, szbuf / 10); dest[szbuf/10] = 0; printf("%2d. [got: %s] ", i+1, dest); vbuf_dbg_rpt(v); assert(i == 9 ? !r : r); assert(!vbuf_is_full(v) && !vbuf_is_empty(v)); } r = vbuf_getblk(v, dest, vbuf_size(v)); assert(r && vbuf_is_empty(v) && !vbuf_is_full(v)); // try unframgented vbuf_clear(v); r = vbuf_putblk(v, src, vbuf_capacity(v)); assert(r && vbuf_is_full(v)); r = vbuf_putblk(v, src, 1); assert(!r); r = vbuf_getblk(v, dest, szbuf-1); assert(r && vbuf_is_empty(v)); r = vbuf_getblk(v, dest, 1); assert(!r && vbuf_is_empty(v)); r = vbuf_putblk(v, src, szbuf); assert(!r && vbuf_is_empty(v)); // string operation vbuf_clear(v); vbuf_putstr(v, "str test(1)"); vbuf_putstr(v, "str test(2)"); vbuf_putstr(v, "str test(3)"); for (i = 0; i < 4; i++) { s = vbuf_getstr(v, dest, sizeof(dest)); printf("put/getstr(%d): %s\n", i+1, s ? s : "(NULL)"); assert(i < 3 ? s != NULL : s == NULL); } // cstr test vbuf_clear(v); vbuf_putstr(v, fragstring); vbuf_dbg_rpt(v); s = vbuf_cstr(v); printf("cstr test(simple): %s\n", s); assert(strcmp(s, fragstring) == 0); vbuf_dbg_fragmentize(v); vbuf_putstr(v, fragstring); vbuf_dbg_rpt(v); s = vbuf_cstr(v); printf("cstr test(unwrap): %s\n", s); assert(strcmp(s, fragstring) == 0); vbuf_dbg_fragmentize(v); vbuf_putblk(v, "*** peek test OK\n", sizeof("*** peek test OK\n")); while (EOF != (i = vbuf_pop(v))) putchar(i); // read/write test vbuf_dbg_fragmentize(v); printf("give me some input for finding location of 't': "); fflush(stdout); vbuf_read(v, 0, VBUF_RWSZ_MIN); printf("index of 't' = %d\n", vbuf_strchr(v, 't')); vbuf_dbg_rpt(v); printf("give me 4 chars: "); fflush(stdout); vbuf_read(v, 0, 4); vbuf_dbg_rpt(v); printf("\n flushing vbuf: ["); fflush(stdout); vbuf_write(v, 1, VBUF_RWSZ_ALL); printf("]\n"); return 0; }