Beispiel #1
0
/* Open a word database object.
   `wdb' specifies the word database object.
   `path' specifies the path of the database file.
   `omode' specifies the connection mode.
   If successful, the return value is true, else, it is false. */
static bool tcwdbopenimpl(TCWDB *wdb, const char *path, int omode){
  assert(wdb && path);
  int bomode = BDBOREADER;
  if(omode & WDBOWRITER){
    bomode = BDBOWRITER;
    if(omode & WDBOCREAT) bomode |= BDBOCREAT;
    if(omode & WDBOTRUNC) bomode |= BDBOTRUNC;
    int64_t bnum = (wdb->etnum / WDBLMEMB) * 2 + 1;
    int bopts = 0;
    if(wdb->opts & WDBTLARGE) bopts |= BDBTLARGE;
    if(wdb->opts & WDBTDEFLATE) bopts |= BDBTDEFLATE;
    if(wdb->opts & WDBTBZIP) bopts |= BDBTBZIP;
    if(wdb->opts & WDBTTCBS) bopts |= BDBTTCBS;
    if(!tcbdbtune(wdb->idx, WDBLMEMB, WDBNMEMB, bnum, WDBAPOW, WDBFPOW, bopts)) return false;
    if(!tcbdbsetlsmax(wdb->idx, WDBLSMAX)) return false;
  }
  if(wdb->lcnum > 0){
    if(!tcbdbsetcache(wdb->idx, wdb->lcnum, wdb->lcnum / 4 + 1)) return false;
  } else {
    if(!tcbdbsetcache(wdb->idx, (omode & WDBOWRITER) ? WDBLCNUMW : WDBLCNUMR, WDBNCNUM))
      return false;
  }
  if(omode & WDBONOLCK) bomode |= BDBONOLCK;
  if(omode & WDBOLCKNB) bomode |= BDBOLCKNB;
  if(!tcbdbopen(wdb->idx, path, bomode)) return false;
  if((omode & WDBOWRITER) && tcbdbrnum(wdb->idx) < 1){
    memcpy(tcbdbopaque(wdb->idx), WDBMAGICDATA, strlen(WDBMAGICDATA));
  } else if(!(omode & WDBONOLCK) &&
            memcmp(tcbdbopaque(wdb->idx), WDBMAGICDATA, strlen(WDBMAGICDATA))){
    tcbdbclose(wdb->idx);
    tcbdbsetecode(wdb->idx, TCEMETA, __FILE__, __LINE__, __func__);
    return 0;
  }
  if(omode & WDBOWRITER){
    wdb->cc = tcmapnew2(WDBCCBNUM);
    wdb->dtokens = tcmapnew2(WDBDTKNBNUM);
    wdb->dids = tcidsetnew(WDBDIDSBNUM);
  }
  wdb->open = true;
  return true;
}
Beispiel #2
0
/* perform inform command */
static int procinform(const char *path, int omode) {
    TCBDB *bdb = tcbdbnew();
    if (!INVALIDHANDLE(g_dbgfd)) tcbdbsetdbgfd(bdb, g_dbgfd);
    tcbdbsetcmpfunc(bdb, mycmpfunc, NULL);
    tcbdbsetcodecfunc(bdb, _tc_recencode, NULL, _tc_recdecode, NULL);
    if (!tcbdbopen(bdb, path, BDBOREADER | omode)) {
        printerr(bdb);
        tcbdbdel(bdb);
        return 1;
    }
    bool err = false;
    const char *npath = tcbdbpath(bdb);
    if (!npath) npath = "(unknown)";
    printf("path: %s\n", npath);
    printf("database type: btree\n");
    uint8_t flags = tcbdbflags(bdb);
    printf("additional flags:");
    if (flags & BDBFOPEN) printf(" open");
    if (flags & BDBFFATAL) printf(" fatal");
    printf("\n");
    TCCMP cmp = tcbdbcmpfunc(bdb);
    printf("comparison function: ");
    if (cmp == tccmplexical) {
        printf("lexical");
    } else if (cmp == tccmpdecimal) {
        printf("decimal");
    } else if (cmp == tccmpint32) {
        printf("int32");
    } else if (cmp == tccmpint64) {
        printf("int64");
    } else {
        printf("custom");
    }
    printf("\n");
    printf("max leaf member: %d\n", tcbdblmemb(bdb));
    printf("max node member: %d\n", tcbdbnmemb(bdb));
    printf("leaf number: %" PRIuMAX "\n", (uint64_t) tcbdblnum(bdb));
    printf("node number: %" PRIuMAX "\n", (uint64_t) tcbdbnnum(bdb));
    printf("bucket number: %" PRIuMAX "\n", (uint64_t) tcbdbbnum(bdb));

#ifndef NDEBUG
    if (bdb->hdb->cnt_writerec >= 0)
        printf("used bucket number: %" PRIdMAX "\n", (int64_t) tcbdbbnumused(bdb));
#endif

    printf("alignment: %u\n", tcbdbalign(bdb));
    printf("free block pool: %u\n", tcbdbfbpmax(bdb));
    printf("inode number: %" PRIdMAX "\n", (int64_t) tcbdbinode(bdb));
    char date[48];
    tcdatestrwww(tcbdbmtime(bdb), INT_MAX, date);
    printf("modified time: %s\n", date);
    uint8_t opts = tcbdbopts(bdb);
    printf("options:");
    if (opts & BDBTLARGE) printf(" large");
    if (opts & BDBTDEFLATE) printf(" deflate");
    if (opts & BDBTBZIP) printf(" bzip");
    if (opts & BDBTTCBS) printf(" tcbs");
    if (opts & BDBTEXCODEC) printf(" excodec");
    printf("\n");
    printf("record number: %" PRIuMAX "\n", (uint64_t) tcbdbrnum(bdb));
    printf("file size: %" PRIuMAX "\n", (uint64_t) tcbdbfsiz(bdb));
    if (!tcbdbclose(bdb)) {
        if (!err) printerr(bdb);
        err = true;
    }
    tcbdbdel(bdb);
    return err ? 1 : 0;
}
Beispiel #3
0
static int control(ErlDrvData handle, unsigned int command, char* buf, int count, char** res, int res_size) {
  tcbdb_drv_t *driver = (tcbdb_drv_t*)handle;
  TCBDB *bdb = driver->bdb;

  int index = 1, tp, sz, version;
  char key[MAX_KEY_SIZE], value[MAX_VALUE_SIZE];
  long key_size, value_size;
  long long long_tmp;
  bool rs;
  const char *value_tmp = NULL;

  ei_x_buff x;
  ei_x_new_with_version(&x);
  if (bdb == NULL && command != OPEN)
    return ei_error(&x, "database_not_opened", res, res_size);

  ei_decode_version(buf, &index, &version);

  switch (command) {
    case OPEN:
      // open(Filepath::string())
      if (bdb == NULL) {
        ei_get_type(buf, &index, &tp, &sz);
        if (tp != ERL_STRING_EXT)
          return ei_error(&x, "invalid_argument", res, res_size);

        TCBDB *bdb = tcbdbnew();
        tcbdbsetmutex(bdb);
        tcbdbsetcache(bdb, 104800, 51200);
        tcbdbsetxmsiz(bdb, 1048576);
        tcbdbtune(bdb, 0, 0, 0, 7, -1, BDBTLARGE);

        char *file = driver_alloc(sz + 1);
        ei_decode_string(buf, &index, file);
        rs = tcbdbopen(bdb, file, BDBOWRITER | BDBOCREAT);
        driver_free(file);
        if (!rs)
          return ei_error(&x, tcbdberrmsg(tcbdbecode(bdb)), res, res_size);
        driver->bdb = bdb;
        ei_x_encode_atom(&x, "ok");
      } else
        return ei_error(&x, "database already opened", res, res_size);
      break;

    case CLOSE:
      tcbdbclose(bdb);
      tcbdbdel(bdb);
      driver->bdb = NULL;
      ei_x_encode_atom(&x, "ok");
      break;

    case PUT:
    case PUTDUP:
    case PUTCAT:
    case PUTKEEP:
      // put({Key::binary(), Value::binary()})
      ei_get_type(buf, &index, &tp, &sz);
      if (tp != ERL_SMALL_TUPLE_EXT || sz != 2)
        return ei_error(&x, "invalid_argument", res, res_size);
      ei_decode_tuple_header(buf, &index, &sz);

      ei_get_type(buf, &index, &tp, &sz);
      if (tp != ERL_BINARY_EXT || sz > MAX_KEY_SIZE)
        return ei_error(&x, "invalid_argument", res, res_size);
      ei_decode_binary(buf, &index, &key[0], &key_size);
      ei_get_type(buf, &index, &tp, &sz);
      if (tp != ERL_BINARY_EXT)
        return ei_error(&x, "invalid_argument", res, res_size);
      if (sz <= MAX_VALUE_SIZE) {
        ei_decode_binary(buf, &index, &value[0], &value_size);
        switch (command) {
          case PUT: rs = tcbdbput(bdb, &key[0], key_size, &value[0], value_size); break;
          case PUTDUP: rs = tcbdbputdup(bdb, &key[0], key_size, &value[0], value_size); break;
          case PUTCAT: rs = tcbdbputcat(bdb, &key[0], key_size, &value[0], value_size); break;
          default: rs = tcbdbputkeep(bdb, &key[0], key_size, &value[0], value_size);
        }
      } else {
        void *p = driver_alloc(sz);
        if (p) {
          ei_decode_binary(buf, &index, p, &value_size);
          switch (command) {
            case PUT: rs = tcbdbput(bdb, &key[0], key_size, p, value_size); break;
            case PUTDUP: rs = tcbdbputdup(bdb, &key[0], key_size, p, value_size); break;
            case PUTCAT: rs = tcbdbputcat(bdb, &key[0], key_size, p, value_size); break;
            default: rs = tcbdbputkeep(bdb, &key[0], key_size, p, value_size);
          }
          driver_free(p);
        } else
          return ei_error(&x, "too long value", res, res_size);
      };
      if (!rs)
        return ei_error(&x, tcbdberrmsg(tcbdbecode(bdb)), res, res_size);
      ei_x_encode_atom(&x, "ok");
      break;

    case GET:
      // get(Key::binary()) -> {ok, Value} | {error, not_found}
      ei_get_type(buf, &index, &tp, &sz);
      if (tp != ERL_BINARY_EXT || sz > MAX_KEY_SIZE)
        return ei_error(&x, "invalid_argument", res, res_size);
      ei_decode_binary(buf, &index, &key[0], &key_size);

      value_tmp = tcbdbget3(bdb, &key[0], key_size, &sz);
      ei_x_encode_tuple_header(&x, 2);
      if (value_tmp != NULL) {
        ei_x_encode_atom(&x, "ok");
        ei_x_encode_binary(&x, value_tmp, sz);
      } else {
        ei_x_encode_atom(&x, "error");
        ei_x_encode_atom(&x, "not_found");
      }
      break;

    case GETDUP:
      // get(Key::binary()) -> {ok, Values}
      ei_get_type(buf, &index, &tp, &sz);
      if (tp != ERL_BINARY_EXT || sz > MAX_KEY_SIZE)
        return ei_error(&x, "invalid_argument", res, res_size);
      ei_decode_binary(buf, &index, &key[0], &key_size);

      TCLIST *vals = tcbdbget4(bdb, key, key_size);
      if (vals) {
        ei_x_encode_tuple_header(&x, 2);
        ei_x_encode_atom(&x, "ok");
        int j;
        for (j=0; j<tclistnum(vals); j++) {
          value_tmp = tclistval(vals, j, &sz);
          ei_x_encode_list_header(&x, 1);
          ei_x_encode_binary(&x, value_tmp, sz);
        }
        tclistdel(vals);
        ei_x_encode_empty_list(&x);
      } else {
        ei_x_encode_tuple_header(&x, 2);
        ei_x_encode_atom(&x, "ok");
        ei_x_encode_empty_list(&x);
      }
      break;

    case REMOVE:
      // remove(Keys::list())
      // remove(Key::binary())
      // remove({Key::binary(), Value::binary()})
      ei_get_type(buf, &index, &tp, &sz);
      if (tp == ERL_LIST_EXT) {
        int count, j;
        ei_decode_list_header(buf, &index, &count);
        for (j=0; j<count; j++) {
          ei_get_type(buf, &index, &tp, &sz);
          if (tp != ERL_BINARY_EXT || sz > MAX_KEY_SIZE)
            return ei_error(&x, "invalid_argument", res, res_size);
          ei_decode_binary(buf, &index, &key[0], &key_size);
          if (!tcbdbout3(bdb, &key[0], key_size))
            return ei_error(&x, tcbdberrmsg(tcbdbecode(bdb)), res, res_size);
        }
        ei_x_encode_atom(&x, "ok");
      } else if (tp == ERL_BINARY_EXT && sz <= MAX_KEY_SIZE) {
        ei_decode_binary(buf, &index, &key[0], &key_size);
        tcbdbout3(bdb, &key[0], key_size);
        ei_x_encode_atom(&x, "ok");
      } else if (tp == ERL_SMALL_TUPLE_EXT && sz == 2) {
        ei_decode_tuple_header(buf, &index, &sz);
        // get key
        ei_get_type(buf, &index, &tp, &sz);
        if (tp != ERL_BINARY_EXT || sz > MAX_KEY_SIZE)
          return ei_error(&x, "invalid_argument", res, res_size);
        ei_decode_binary(buf, &index, &key[0], &key_size);
        // get value
        ei_get_type(buf, &index, &tp, &sz);
        if (tp != ERL_BINARY_EXT || sz > MAX_VALUE_SIZE)
          return ei_error(&x, "invalid_argument", res, res_size);
        ei_decode_binary(buf, &index, &value[0], &value_size);
        // remove by key&value
        BDBCUR *cur = tcbdbcurnew(bdb);
        if (!tcbdbcurjump(cur, &key[0], key_size))
          return ei_error(&x, "record_not_found", res, res_size);
        
        bool removed = false, not_found = false;
        while (!removed && !not_found) {
          int cur_key_size, cur_val_size;
          const void *curkey = tcbdbcurkey3(cur, &cur_key_size);
          if (cur_key_size == key_size && memcmp(curkey, key, key_size) == 0) {
            const void *curval = tcbdbcurval3(cur, &cur_val_size);
            if (cur_val_size == value_size && memcmp(curval, value, value_size) == 0) {
              tcbdbcurout(cur);
              removed = true;
            } else
              if (!tcbdbcurnext(cur))
                not_found = true;
          } else not_found = true;
        }
        if (not_found) ei_x_encode_atom(&x, "not_found");
        else ei_x_encode_atom(&x, "ok");
        
      } else
        return ei_error(&x, "invalid_argument", res, res_size);
      break;

    case RANGE:
      /*
       * range({Prefix::binary(), limit:integer()})
       * range({StartKey::binary(), BeginInclusion::boolean(), EndKey::binary(), EndInclusion::binary(), limit:integer()})
       */
      ei_get_type(buf, &index, &tp, &sz);
      if (tp != ERL_SMALL_TUPLE_EXT || sz < 2)
        return ei_error(&x, "invalid_argument", res, res_size);
      ei_decode_tuple_header(buf, &index, &sz);

      ei_get_type(buf, &index, &tp, &sz);
      if (tp == ERL_BINARY_EXT && sz <= MAX_KEY_SIZE) {
        char keys[MAX_KEY_SIZE], keyf[MAX_KEY_SIZE];
        long keys_size, keyf_size;
        int keys_inc, keyf_inc;
        long max = -1;
        TCLIST *range;

        ei_decode_binary(buf, &index, &keys[0], &keys_size);
        ei_get_type(buf, &index, &tp, &sz);
        if (tp == ERL_ATOM_EXT) {
          // range
          ei_decode_boolean(buf, &index, &keys_inc);
          ei_get_type(buf, &index, &tp, &sz);
          if (tp != ERL_BINARY_EXT || sz > MAX_KEY_SIZE)
            return ei_error(&x, "invalid_argument", res, res_size);
          ei_decode_binary(buf, &index, &keyf[0], &keyf_size);
          ei_get_type(buf, &index, &tp, &sz);
          if (tp != ERL_ATOM_EXT)
            return ei_error(&x, "invalid_argument", res, res_size);
          ei_decode_boolean(buf, &index, &keyf_inc);

          ei_get_type(buf, &index, &tp, &sz);
          if (tp != ERL_INTEGER_EXT)
            return ei_error(&x, "invalid_argument", res, res_size);
          ei_decode_long(buf, &index, &max);

          range = tcbdbrange(bdb, &keys[0], keys_size, keys_inc == 1, &keyf[0], keyf_size, keyf_inc == 1, max);
        } else if (tp == ERL_INTEGER_EXT) {
          // prefix
          ei_get_type(buf, &index, &tp, &sz);
          if (tp != ERL_INTEGER_EXT)
            return ei_error(&x, "invalid_argument", res, res_size);
          ei_decode_long(buf, &index, &max);

          range = tcbdbfwmkeys(bdb, &keys[0], keys_size, max);
        } else
          return ei_error(&x, "invalid_argument", res, res_size);

        const char *key;
        int key_size, value_size;
        int idx, cnt = 0, rcount = tclistnum(range);

        ei_x_encode_tuple_header(&x, 2);
        ei_x_encode_atom(&x, "ok");

        BDBCUR *cur = tcbdbcurnew(bdb);
        for (idx=0; idx<rcount; idx++) {
          key = tclistval(range, idx, &key_size);
          TCLIST *vals = tcbdbget4(bdb, key, key_size);
          if (vals) {
            int j;
            for (j=0; j<tclistnum(vals); j++) {
              ei_x_encode_list_header(&x, 1);
              value_tmp = tclistval(vals, j, &value_size);
              ei_x_encode_binary(&x, value_tmp, value_size);
              if (max >= 0 && ++cnt >= max) break;
            }
            tclistdel(vals);
          }
          idx++;
        }
        tcbdbcurdel(cur);
        tclistdel(range);
        ei_x_encode_empty_list(&x);

      } else
        return ei_error(&x, "invalid_argument", res, res_size);
      break;

    case SYNC:
      // sync()
      if (!tcbdbsync(bdb))
        return ei_error(&x, tcbdberrmsg(tcbdbecode(bdb)), res, res_size);
      ei_x_encode_atom(&x, "ok");
      break;

    case INFO:
      // info()
      ei_x_encode_tuple_header(&x, 3);
      ei_x_encode_atom(&x, "ok");
      long_tmp = tcbdbrnum(bdb);
      ei_x_encode_longlong(&x, long_tmp);
      long_tmp = tcbdbfsiz(bdb);
      ei_x_encode_longlong(&x, long_tmp);
      break;

    case ITERATE:
      // Read(none) -> {ok, Key} | {error, not_found}
      // Read(Key::binary()) -> {ok, Key} | {error, not_found}
      ei_get_type(buf, &index, &tp, &sz);
      BDBCUR *cur = tcbdbcurnew(bdb);
      if (tp == ERL_BINARY_EXT && sz <= MAX_KEY_SIZE) {
        ei_decode_binary(buf, &index, &key[0], &key_size);
        rs = tcbdbcurjump(cur, &key[0], key_size) && tcbdbcurnext(cur);
      } else
        rs = tcbdbcurfirst(cur);
      if (rs) {
        int key_size;
        const char *key = tcbdbcurkey3(cur, &key_size);

        ei_x_encode_tuple_header(&x, 2);
        ei_x_encode_atom(&x, "ok");
        ei_x_encode_binary(&x, key, key_size);
        tcbdbcurdel(cur);
      } else {
        tcbdbcurdel(cur);
        return ei_error(&x, "not_found", res, res_size);
      }
      break;

    case VANISH:
      // vanish() -> ok
      if (!tcbdbvanish(bdb))
        return ei_error(&x, tcbdberrmsg(tcbdbecode(bdb)), res, res_size);
      ei_x_encode_atom(&x, "ok");
      break;

    case BACKUP:
      // backup(path::string()) -> ok | {error, Reason}
      ei_get_type(buf, &index, &tp, &sz);
      if (tp == ERL_STRING_EXT) {
        char *file = driver_alloc(sz + 1);
        ei_decode_string(buf, &index, file);
        if (tcbdbcopy(driver->bdb, file))
          ei_x_encode_atom(&x, "ok");
        else
          return ei_error(&x, tcbdberrmsg(tcbdbecode(bdb)), res, res_size);
      } else
        return ei_error(&x, "invalid_argument", res, res_size);
      break;

    default:
      return ei_error(&x, "invalid_command", res, res_size);
  }

  if (res_size < x.index)
    (*res) = (char *)driver_alloc(x.index);
  int n = x.index;
  memcpy(*res, x.buff, x.index);
  ei_x_free(&x);
  return n;
};
Beispiel #4
0
/* perform inform command */
static int procinform(const char *path, int omode){
  TCTDB *tdb = tctdbnew();
  if(g_dbgfd != INVALID_HANDLE_VALUE) tctdbsetdbgfd(tdb, g_dbgfd);
  tctdbsetcodecfunc(tdb, _tc_recencode, NULL, _tc_recdecode, NULL);
  if(!tctdbopen(tdb, path, TDBOREADER | omode)){
    printerr(tdb);
    tctdbdel(tdb);
    return 1;
  }
  bool err = false;
  const char *npath = tctdbpath(tdb);
  if(!npath) npath = "(unknown)";
  printf("path: %s\n", npath);
  printf("database type: table\n");
  uint8_t flags = tctdbflags(tdb);
  printf("additional flags:");
  if(flags & TDBFOPEN) printf(" open");
  if(flags & TDBFFATAL) printf(" fatal");
  printf("\n");
  printf("bucket number: %llu\n", (unsigned long long)tctdbbnum(tdb));
  if(tdb->hdb->cnt_writerec >= 0)
    printf("used bucket number: %lld\n", (long long)tctdbbnumused(tdb));
  printf("alignment: %u\n", tctdbalign(tdb));
  printf("free block pool: %u\n", tctdbfbpmax(tdb));
  printf("index number: %d\n", tctdbinum(tdb));
  TDBIDX *idxs = tdb->idxs;
  int inum = tdb->inum;
  for(int i = 0; i < inum; i++){
    TDBIDX *idxp = idxs + i;
    switch(idxp->type){
      case TDBITLEXICAL:
        printf("  name=%s, type=lexical, rnum=%lld, fsiz=%lld\n",
               idxp->name, (long long)tcbdbrnum(idxp->db), (long long)tcbdbfsiz(idxp->db));
        break;
      case TDBITDECIMAL:
        printf("  name=%s, type=decimal, rnum=%lld, fsiz=%lld\n",
               idxp->name, (long long)tcbdbrnum(idxp->db), (long long)tcbdbfsiz(idxp->db));
        break;
      case TDBITTOKEN:
        printf("  name=%s, type=token, rnum=%lld, fsiz=%lld\n",
               idxp->name, (long long)tcbdbrnum(idxp->db), (long long)tcbdbfsiz(idxp->db));
        break;
      case TDBITQGRAM:
        printf("  name=%s, type=qgram, rnum=%lld, fsiz=%lld\n",
               idxp->name, (long long)tcbdbrnum(idxp->db), (long long)tcbdbfsiz(idxp->db));
        break;
    }
  }
  printf("unique ID seed: %lld\n", (long long)tctdbuidseed(tdb));
  printf("inode number: %lld\n", (long long)tctdbinode(tdb));
  char date[48];
  tcdatestrwww(tctdbmtime(tdb), INT_MAX, date);
  printf("modified time: %s\n", date);
  uint8_t opts = tctdbopts(tdb);
  printf("options:");
  if(opts & TDBTLARGE) printf(" large");
  if(opts & TDBTDEFLATE) printf(" deflate");
  if(opts & TDBTBZIP) printf(" bzip");
  if(opts & TDBTTCBS) printf(" tcbs");
  if(opts & TDBTEXCODEC) printf(" excodec");
  printf("\n");
  printf("record number: %llu\n", (unsigned long long)tctdbrnum(tdb));
  printf("file size: %llu\n", (unsigned long long)tctdbfsiz(tdb));
  if(!tctdbclose(tdb)){
    if(!err) printerr(tdb);
    err = true;
  }
  tctdbdel(tdb);
  return err ? 1 : 0;
}
Beispiel #5
0
/* Get the number of tokens of a word database object. */
uint64_t tcwdbtnum(TCWDB *wdb){
  assert(wdb);
  return tcbdbrnum(wdb->idx);
}
/* rnum */
JNIEXPORT jlong JNICALL Java_tokyocabinet_BDB_rnum
(JNIEnv *env, jobject self){
  TCBDB *bdb = (TCBDB *)(intptr_t)(*env)->GetLongField(env, self, bdb_fid_ptr);
  return tcbdbrnum(bdb);
}