/* recursive to search the matched record */ static void _xdb_rec_get(xdb_t x, xrec_t rec, const char *key, int len) { unsigned char buf[XDB_MAXKLEN + 2]; // greater than: 255 int cmp; if (rec->me.len == 0) return; // [left][right] = 16\0 _xdb_read_data(x, buf, rec->me.off + 16, len + 1); cmp = memcmp(key, buf+1, len); if (!cmp) cmp = len - buf[0]; if (cmp > 0) { // right rec->poff = rec->me.off + sizeof(xptr_st); _xdb_read_data(x, &rec->me, rec->me.off + sizeof(xptr_st), sizeof(xptr_st)); _xdb_rec_get(x, rec, key, len); } else if (cmp < 0) { // left rec->poff = rec->me.off; _xdb_read_data(x, &rec->me, rec->me.off, sizeof(xptr_st)); _xdb_rec_get(x, rec, key, len); } else { // found! rec->value.off = rec->me.off + 17 + len; rec->value.len = rec->me.len - 17 - len; } }
static void _xdb_count_nodes(xdb_t x, xptr_t ptr, int *count) { int off; if (ptr->len == 0) return; *count += 1; off = ptr->off; /* left & right */ _xdb_read_data(x, ptr, off, sizeof(xptr_st)); _xdb_count_nodes(x, ptr, count); _xdb_read_data(x, ptr, off + sizeof(xptr_st), sizeof(xptr_st)); _xdb_count_nodes(x, ptr, count); }
static void _xdb_load_nodes(xdb_t x, xptr_t ptr, xcmper_st *nodes, int *count) { int i; unsigned char buf[XDB_MAXKLEN + 18]; if (ptr->len == 0) return; i = sizeof(buf)-1; if (i > (int)ptr->len) i = ptr->len; _xdb_read_data(x, buf, ptr->off, i); i = *count; nodes[i].ptr.off = ptr->off; nodes[i].ptr.len = ptr->len; nodes[i].key = (char *) _mem_ndup(buf + 17, buf[16]); *count = i+1; /* left & right */ memcpy(ptr, buf, sizeof(xptr_st)); _xdb_load_nodes(x, ptr, nodes, count); memcpy(ptr, buf + sizeof(xptr_st), sizeof(xptr_st)); _xdb_load_nodes(x, ptr, nodes, count); }
static void _xdb_draw_node(xdb_t x, xptr_t ptr, struct draw_arg *arg, int depth, char *icon1) { char *icon2; icon2 = malloc(strlen(icon1) + 4); strcpy(icon2, icon1); // output the flag & icon if (arg->flag == 'T') printf("(T) "); else { printf("%s", icon2); if (arg->flag == 'L') { strcat(icon2, " ┃"); printf(" ┟(L) "); } else { strcat(icon2, " "); printf(" └(R) "); } } // draw the node data if (ptr->len == 0) printf("<NULL>\n"); else { unsigned char buf[XDB_MAXKLEN + 18]; // greater than 18 = sizeof(xptr_st)*2+1 int vlen, voff; vlen = sizeof(buf) - 1; if (vlen > ptr->len) vlen = ptr->len; _xdb_read_data(x, buf, ptr->off, vlen); vlen = ptr->len - buf[16] - 17; voff = ptr->off + buf[16] + 17; printf("%.*s (vlen=%d, voff=%d)\n", buf[16], buf+17, vlen, voff); arg->count++; depth++; if (depth > arg->depth) arg->depth = depth; // draw the left & right; arg->flag = 'L'; memcpy(ptr, buf, sizeof(xptr_st)); _xdb_draw_node(x, ptr, arg, depth, icon2); arg->flag = 'R'; memcpy(ptr, buf + sizeof(xptr_st), sizeof(xptr_st)); _xdb_draw_node(x, ptr, arg, depth, icon2); } free(icon2); }
/* write mode */ void xdb_nput(xdb_t x, void *value, unsigned int vlen, const char *key, int len) { xrec_st rec; if (x == NULL || x->fd < 0 || key == NULL || len > XDB_MAXKLEN) return; /* not found, return the poff(for write) */ _xdb_rec_find(x, key, len, &rec); if (rec.value.len > 0 && vlen <= rec.value.len) { /* just replace */ if (vlen > 0) { lseek(x->fd, rec.value.off, SEEK_SET); write(x->fd, value, vlen); } if (vlen < rec.value.len) { vlen += rec.me.len - rec.value.len; lseek(x->fd, rec.poff + 4, SEEK_SET); write(x->fd, &vlen, sizeof(vlen)); } } else if (vlen > 0) { /* insert for new data */ unsigned char buf[512]; xptr_st pnew; pnew.off = x->fsize; memset(buf, 0, sizeof(buf)); pnew.len = rec.me.len - rec.value.len; if (pnew.len > 0) { _xdb_read_data(x, buf, rec.me.off, pnew.len); } else { buf[16] = len; // key len strncpy(buf + 17, key, len); pnew.len = 17 + len; } lseek(x->fd, pnew.off, SEEK_SET); write(x->fd, buf, pnew.len); write(x->fd, value, vlen); pnew.len += vlen; x->fsize += pnew.len; /* update noff & vlen -> poff */ lseek(x->fd, rec.poff, SEEK_SET); write(x->fd, &pnew, sizeof(pnew)); } }
static xrec_t _xdb_rec_find(xdb_t x, const char *key, int len, xrec_t rec) { int i; if (rec == NULL) rec = (xrec_t) malloc(sizeof(xrec_st)); memset(rec, 0, sizeof(xrec_st)); i = (x->prime > 1 ? _xdb_hasher(x, key, len) : 0); rec->poff = i * sizeof(xptr_st) + sizeof(struct xdb_header); _xdb_read_data(x, &rec->me, rec->poff, sizeof(xptr_st)); _xdb_rec_get(x, rec, key, len); return rec; }
/* read mode (value require free by user) */ void *xdb_nget(xdb_t x, const char *key, int len, unsigned int *vlen) { xrec_st rec; void *value = NULL; if (x == NULL || key == NULL || len > XDB_MAXKLEN) return NULL; /* not found, return the poff(for write) */ _xdb_rec_find(x, key, len, &rec); if (rec.value.len > 0) { /* auto append one byte with '\0' */ value = malloc(rec.value.len + 1); if (vlen != NULL) *vlen = rec.value.len; _xdb_read_data(x, value, rec.value.off, rec.value.len); } return value; }
void xdb_draw(xdb_t x) { int i; struct draw_arg arg; xptr_st ptr; if (!x) return; xdb_version(x); for (i = 0; i < x->prime; i++) { arg.depth = 0; arg.count = 0; arg.flag = 'T'; _xdb_read_data(x, &ptr, i * sizeof(xptr_st) + sizeof(struct xdb_header), sizeof(xptr_st)); _xdb_draw_node(x, &ptr, &arg, 0, ""); printf("-----------------------------------------\n"); printf("Tree(xdb) [%d] max_depth: %d nodes_num: %d\n", i, arg.depth, arg.count); } }