func directMultiGet(kvstore *goforestdb.KVStore, keysIn [][]byte) ( valsOut [][]byte, valsRelease func(), err error) { keys := make([]*C.char, len(keysIn)) key_lens := make([]C.size_t, len(keysIn)) vals := make([]*C.char, len(keysIn)) val_lens := make([]C.size_t, len(keysIn)) for i, key := range keysIn { keys[i] = (*C.char)(unsafe.Pointer(&key[0])) key_lens[i] = (C.size_t)(len(key)) } valsRelease = func() { C.blevex_forestdb_free_bufs( (C.size_t)(len(vals)), (**C.char)(unsafe.Pointer(&vals[0]))) for i := range vals { vals[i] = nil } } errNo := C.blevex_forestdb_multi_get( (*C.fdb_kvs_handle)(kvstore.Handle()), (C.size_t)(len(keys)), (**C.char)(unsafe.Pointer(&keys[0])), (*C.size_t)(unsafe.Pointer(&key_lens[0])), (**C.char)(unsafe.Pointer(&vals[0])), (*C.size_t)(unsafe.Pointer(&val_lens[0]))) if int(errNo) != 0 { valsRelease() return nil, nil, goforestdb.Error(errNo) } valsOut = make([][]byte, len(vals)) for i, val := range vals { if val != nil { valsOut[i] = charToByte(val, val_lens[i]) } } return valsOut, valsRelease, nil }
func (b *BatchEx) apply() error { // Hold onto final merge key/val bytes so GC doesn't collect them // until we're done. var mergeBytes [][]byte if len(b.merge.Merges) > 0 { mergeBytes = make([][]byte, 0, len(b.merge.Merges)*2) mergeKeys := make([][]byte, len(b.merge.Merges)) mergeOps := make([][][]byte, len(b.merge.Merges)) i := 0 for key, ops := range b.merge.Merges { mergeKeys[i] = []byte(key) mergeOps[i] = ops i += 1 } currVals, releaseVals, err := directMultiGet(b.w.kvstore, mergeKeys) if err != nil { return err } defer releaseVals() for i, key := range mergeKeys { mergedVal, ok := b.w.store.mo.FullMerge(key, currVals[i], mergeOps[i]) if !ok { return fmt.Errorf("forestdb BatchEx merge operator failure,"+ " key: %s, currVal: %q, mergeOps: %#v, i: %d", key, currVals[i], mergeOps[i], i) } mergeBytes = append(mergeBytes, key, mergedVal) b.Set(key, mergedVal) } } var num_sets C.int var set_keys **C.char var set_keys_sizes *C.size_t var set_vals **C.char var set_vals_sizes *C.size_t var num_deletes C.int var delete_keys **C.char var delete_keys_sizes *C.size_t if b.num_sets > 0 { num_sets = (C.int)(b.num_sets) set_keys = (**C.char)(unsafe.Pointer(&b.set_keys[0])) set_keys_sizes = (*C.size_t)(unsafe.Pointer(&b.set_keys_sizes[0])) set_vals = (**C.char)(unsafe.Pointer(&b.set_vals[0])) set_vals_sizes = (*C.size_t)(unsafe.Pointer(&b.set_vals_sizes[0])) } if b.num_deletes > 0 { num_deletes = (C.int)(b.num_deletes) delete_keys = (**C.char)(unsafe.Pointer(&b.delete_keys[0])) delete_keys_sizes = (*C.size_t)(unsafe.Pointer(&b.delete_keys_sizes[0])) } errNo := C.blevex_forestdb_execute_direct_batch( (*C.fdb_kvs_handle)(b.w.kvstore.Handle()), num_sets, set_keys, set_keys_sizes, set_vals, set_vals_sizes, num_deletes, delete_keys, delete_keys_sizes) if int(errNo) != 0 { return goforestdb.Error(errNo) } if mergeBytes != nil { // Ok to let GC have mergeBytes now. mergeBytes = nil } return nil }