diff --git a/compaction_filter.go b/compaction_filter.go index 43e9617b..bcb61557 100644 --- a/compaction_filter.go +++ b/compaction_filter.go @@ -23,21 +23,24 @@ type CompactionFilter interface { // The name of the compaction filter, for logging Name() string + CName() *C.char } // NewNativeCompactionFilter creates a CompactionFilter object. func NewNativeCompactionFilter(c *C.rocksdb_compactionfilter_t) CompactionFilter { - return nativeCompactionFilter{c} + return nativeCompactionFilter{c, C.CString("")} } type nativeCompactionFilter struct { - c *C.rocksdb_compactionfilter_t + c *C.rocksdb_compactionfilter_t + cname *C.char } func (c nativeCompactionFilter) Filter(level int, key, val []byte) (remove bool, newVal []byte) { return false, nil } -func (c nativeCompactionFilter) Name() string { return "" } +func (c nativeCompactionFilter) Name() string { return "" } +func (c nativeCompactionFilter) CName() *C.char { return c.cname } // Hold references to compaction filters. var compactionFilters = NewCOWList() @@ -64,5 +67,5 @@ func gorocksdb_compactionfilter_filter(idx int, cLevel C.int, cKey *C.char, cKey //export gorocksdb_compactionfilter_name func gorocksdb_compactionfilter_name(idx int) *C.char { - return stringToChar(compactionFilters.Get(idx).(CompactionFilter).Name()) + return compactionFilters.Get(idx).(CompactionFilter).CName() } diff --git a/compaction_filter_test.go b/compaction_filter_test.go index 1dfcd63e..e1ee8d8c 100644 --- a/compaction_filter_test.go +++ b/compaction_filter_test.go @@ -15,18 +15,16 @@ func TestCompactionFilter(t *testing.T) { deleteKey = []byte("delete") ) db := newTestDB(t, "TestCompactionFilter", func(opts *Options) { - opts.SetCompactionFilter(&mockCompactionFilter{ - filter: func(level int, key, val []byte) (remove bool, newVal []byte) { - if bytes.Equal(key, changeKey) { - return false, changeValNew - } - if bytes.Equal(key, deleteKey) { - return true, val - } - t.Errorf("key %q not expected during compaction", key) - return false, nil - }, - }) + opts.SetCompactionFilter(NewMockCompactionFilter(func(level int, key, val []byte) (remove bool, newVal []byte) { + if bytes.Equal(key, changeKey) { + return false, changeValNew + } + if bytes.Equal(key, deleteKey) { + return true, val + } + t.Errorf("key %q not expected during compaction", key) + return false, nil + })) }) defer db.Close() @@ -51,11 +49,7 @@ func TestCompactionFilter(t *testing.T) { ensure.True(t, v2.Data() == nil) } -type mockCompactionFilter struct { - filter func(level int, key, val []byte) (remove bool, newVal []byte) -} - -func (m *mockCompactionFilter) Name() string { return "gorocksdb.test" } -func (m *mockCompactionFilter) Filter(level int, key, val []byte) (bool, []byte) { - return m.filter(level, key, val) +func TestCompactionFilterName(t *testing.T) { + cf := NewMockCompactionFilter(nil) + ensure.DeepEqual(t, cf.Name(), GetCName(cf.CName())) } diff --git a/compaction_filter_test_mockstub.go b/compaction_filter_test_mockstub.go new file mode 100644 index 00000000..57668695 --- /dev/null +++ b/compaction_filter_test_mockstub.go @@ -0,0 +1,21 @@ +package gorocksdb + +import "C" + +func NewMockCompactionFilter(f func(level int, key, val []byte) (remove bool, newVal []byte)) CompactionFilter { + return &mockCompactionFilter{ + filter: f, + } +} + +type mockCompactionFilter struct { + filter func(level int, key, val []byte) (remove bool, newVal []byte) +} + +func (m *mockCompactionFilter) Name() string { return "gorocksdb.test" } +func (m *mockCompactionFilter) CName() *C.char { return C.CString("gorocksdb.test") } +func (m *mockCompactionFilter) Filter(level int, key, val []byte) (bool, []byte) { + return m.filter(level, key, val) +} + +func GetCName(c *C.char) string { return C.GoString(c) } diff --git a/comparator.go b/comparator.go index 9e30c1fb..d25b4189 100644 --- a/comparator.go +++ b/comparator.go @@ -14,19 +14,22 @@ type Comparator interface { // The name of the comparator. Name() string + CName() *C.char } // NewNativeComparator creates a Comparator object. func NewNativeComparator(c *C.rocksdb_comparator_t) Comparator { - return nativeComparator{c} + return nativeComparator{c, C.CString("")} } type nativeComparator struct { - c *C.rocksdb_comparator_t + c *C.rocksdb_comparator_t + cname *C.char } func (c nativeComparator) Compare(a, b []byte) int { return 0 } func (c nativeComparator) Name() string { return "" } +func (c nativeComparator) CName() *C.char { return c.cname } // Hold references to comperators. var comperators = NewCOWList() @@ -44,5 +47,5 @@ func gorocksdb_comparator_compare(idx int, cKeyA *C.char, cKeyALen C.size_t, cKe //export gorocksdb_comparator_name func gorocksdb_comparator_name(idx int) *C.char { - return stringToChar(comperators.Get(idx).(Comparator).Name()) + return comperators.Get(idx).(Comparator).CName() } diff --git a/comparator_test.go b/comparator_test.go index 76f3e565..8642b6d1 100644 --- a/comparator_test.go +++ b/comparator_test.go @@ -1,7 +1,6 @@ package gorocksdb import ( - "bytes" "testing" "github.com/facebookgo/ensure" @@ -9,7 +8,7 @@ import ( func TestComparator(t *testing.T) { db := newTestDB(t, "TestComparator", func(opts *Options) { - opts.SetComparator(&bytesReverseComparator{}) + opts.SetComparator(NewMockBytesReverseComparator()) }) defer db.Close() @@ -38,10 +37,3 @@ func TestComparator(t *testing.T) { // ensure that the order is correct ensure.DeepEqual(t, actualKeys, givenKeys) } - -type bytesReverseComparator struct{} - -func (cmp *bytesReverseComparator) Name() string { return "gorocksdb.bytes-reverse" } -func (cmp *bytesReverseComparator) Compare(a, b []byte) int { - return bytes.Compare(a, b) * -1 -} diff --git a/comparator_test_mockstub.go b/comparator_test_mockstub.go new file mode 100644 index 00000000..19fffcb1 --- /dev/null +++ b/comparator_test_mockstub.go @@ -0,0 +1,16 @@ +package gorocksdb + +import "bytes" +import "C" + +func NewMockBytesReverseComparator() Comparator { + return &bytesReverseComparator{} +} + +type bytesReverseComparator struct{} + +func (cmp *bytesReverseComparator) Name() string { return "gorocksdb.bytes-reverse" } +func (cmp *bytesReverseComparator) CName() *C.char { return C.CString("gorocksdb.bytes-reverse") } +func (cmp *bytesReverseComparator) Compare(a, b []byte) int { + return bytes.Compare(a, b) * -1 +} diff --git a/filter_policy.go b/filter_policy.go index 71e74e89..c6698c1f 100644 --- a/filter_policy.go +++ b/filter_policy.go @@ -19,20 +19,23 @@ type FilterPolicy interface { // Return the name of this policy. Name() string + CName() *C.char } // NewNativeFilterPolicy creates a FilterPolicy object. func NewNativeFilterPolicy(c *C.rocksdb_filterpolicy_t) FilterPolicy { - return nativeFilterPolicy{c} + return nativeFilterPolicy{c, C.CString("")} } type nativeFilterPolicy struct { - c *C.rocksdb_filterpolicy_t + c *C.rocksdb_filterpolicy_t + cname *C.char } func (fp nativeFilterPolicy) CreateFilter(keys [][]byte) []byte { return nil } func (fp nativeFilterPolicy) KeyMayMatch(key []byte, filter []byte) bool { return false } func (fp nativeFilterPolicy) Name() string { return "" } +func (fp nativeFilterPolicy) CName() *C.char { return fp.cname } // NewBloomFilter returns a new filter policy that uses a bloom filter with approximately // the specified number of bits per key. A good value for bits_per_key @@ -79,5 +82,5 @@ func gorocksdb_filterpolicy_key_may_match(idx int, cKey *C.char, cKeyLen C.size_ //export gorocksdb_filterpolicy_name func gorocksdb_filterpolicy_name(idx int) *C.char { - return stringToChar(filterPolicies.Get(idx).(FilterPolicy).Name()) + return filterPolicies.Get(idx).(FilterPolicy).CName() } diff --git a/filter_policy_test.go b/filter_policy_test.go index c15aa1b6..089aa01a 100644 --- a/filter_policy_test.go +++ b/filter_policy_test.go @@ -23,19 +23,18 @@ func TestFilterPolicy(t *testing.T) { createFilterCalled = false keyMayMatchCalled = false ) - policy := &mockFilterPolicy{ - createFilter: func(keys [][]byte) []byte { + policy := NewMockFilterPolicy( + func(keys [][]byte) []byte { createFilterCalled = true ensure.DeepEqual(&fatalAsError{t}, keys, givenKeys) return givenFilter }, - keyMayMatch: func(key, filter []byte) bool { + func(key, filter []byte) bool { keyMayMatchCalled = true ensure.DeepEqual(&fatalAsError{t}, key, givenKeys[0]) ensure.DeepEqual(&fatalAsError{t}, filter, givenFilter) return true - }, - } + }) db := newTestDB(t, "TestFilterPolicy", func(opts *Options) { blockOpts := NewDefaultBlockBasedTableOptions() @@ -61,16 +60,3 @@ func TestFilterPolicy(t *testing.T) { ensure.Nil(t, err) ensure.True(t, keyMayMatchCalled) } - -type mockFilterPolicy struct { - createFilter func(keys [][]byte) []byte - keyMayMatch func(key, filter []byte) bool -} - -func (m *mockFilterPolicy) Name() string { return "gorocksdb.test" } -func (m *mockFilterPolicy) CreateFilter(keys [][]byte) []byte { - return m.createFilter(keys) -} -func (m *mockFilterPolicy) KeyMayMatch(key, filter []byte) bool { - return m.keyMayMatch(key, filter) -} diff --git a/filter_policy_test_mockstub.go b/filter_policy_test_mockstub.go new file mode 100644 index 00000000..2209194a --- /dev/null +++ b/filter_policy_test_mockstub.go @@ -0,0 +1,21 @@ +package gorocksdb + +import "C" + +func NewMockFilterPolicy(cf func(keys [][]byte) []byte, kmm func(key, filter []byte) bool) FilterPolicy { + return &mockFilterPolicy{cf, kmm} +} + +type mockFilterPolicy struct { + createFilter func(keys [][]byte) []byte + keyMayMatch func(key, filter []byte) bool +} + +func (m *mockFilterPolicy) Name() string { return "gorocksdb.test" } +func (m *mockFilterPolicy) CName() *C.char { return C.CString("gorocksdb.test") } +func (m *mockFilterPolicy) CreateFilter(keys [][]byte) []byte { + return m.createFilter(keys) +} +func (m *mockFilterPolicy) KeyMayMatch(key, filter []byte) bool { + return m.keyMayMatch(key, filter) +} diff --git a/merge_operator.go b/merge_operator.go index cbf66da5..5ec053b8 100644 --- a/merge_operator.go +++ b/merge_operator.go @@ -45,15 +45,17 @@ type MergeOperator interface { // The name of the MergeOperator. Name() string + CName() *C.char } // NewNativeMergeOperator creates a MergeOperator object. func NewNativeMergeOperator(c *C.rocksdb_mergeoperator_t) MergeOperator { - return nativeMergeOperator{c} + return nativeMergeOperator{c, C.CString("")} } type nativeMergeOperator struct { - c *C.rocksdb_mergeoperator_t + c *C.rocksdb_mergeoperator_t + cname *C.char } func (mo nativeMergeOperator) FullMerge(key, existingValue []byte, operands [][]byte) ([]byte, bool) { @@ -62,7 +64,8 @@ func (mo nativeMergeOperator) FullMerge(key, existingValue []byte, operands [][] func (mo nativeMergeOperator) PartialMerge(key, leftOperand, rightOperand []byte) ([]byte, bool) { return nil, false } -func (mo nativeMergeOperator) Name() string { return "" } +func (mo nativeMergeOperator) Name() string { return "" } +func (mo nativeMergeOperator) CName() *C.char { return mo.cname } // Hold references to merge operators. var mergeOperators = NewCOWList() @@ -123,5 +126,5 @@ func gorocksdb_mergeoperator_partial_merge_multi(idx int, cKey *C.char, cKeyLen //export gorocksdb_mergeoperator_name func gorocksdb_mergeoperator_name(idx int) *C.char { - return stringToChar(mergeOperators.Get(idx).(MergeOperator).Name()) + return mergeOperators.Get(idx).(MergeOperator).CName() } diff --git a/merge_operator_test.go b/merge_operator_test.go index fd7e0887..4e7c9653 100644 --- a/merge_operator_test.go +++ b/merge_operator_test.go @@ -13,14 +13,13 @@ func TestMergeOperator(t *testing.T) { givenVal2 = []byte("bar") givenMerged = []byte("foobar") ) - merger := &mockMergeOperator{ - fullMerge: func(key, existingValue []byte, operands [][]byte) ([]byte, bool) { - ensure.DeepEqual(&fatalAsError{t}, key, givenKey) - ensure.DeepEqual(&fatalAsError{t}, existingValue, givenVal1) - ensure.DeepEqual(&fatalAsError{t}, operands, [][]byte{givenVal2}) - return givenMerged, true - }, - } + merger := NewMockMergeOperator(func(key, existingValue []byte, operands [][]byte) ([]byte, bool) { + ensure.DeepEqual(&fatalAsError{t}, key, givenKey) + ensure.DeepEqual(&fatalAsError{t}, existingValue, givenVal1) + ensure.DeepEqual(&fatalAsError{t}, operands, [][]byte{givenVal2}) + return givenMerged, true + }, nil) + db := newTestDB(t, "TestMergeOperator", func(opts *Options) { opts.SetMergeOperator(merger) }) @@ -39,16 +38,3 @@ func TestMergeOperator(t *testing.T) { ensure.Nil(t, err) ensure.DeepEqual(t, v1.Data(), givenMerged) } - -type mockMergeOperator struct { - fullMerge func(key, existingValue []byte, operands [][]byte) ([]byte, bool) - partialMerge func(key, leftOperand, rightOperand []byte) ([]byte, bool) -} - -func (m *mockMergeOperator) Name() string { return "gorocksdb.test" } -func (m *mockMergeOperator) FullMerge(key, existingValue []byte, operands [][]byte) ([]byte, bool) { - return m.fullMerge(key, existingValue, operands) -} -func (m *mockMergeOperator) PartialMerge(key, leftOperand, rightOperand []byte) ([]byte, bool) { - return m.partialMerge(key, leftOperand, rightOperand) -} diff --git a/merge_operator_test_mockstub.go b/merge_operator_test_mockstub.go new file mode 100644 index 00000000..d56359dc --- /dev/null +++ b/merge_operator_test_mockstub.go @@ -0,0 +1,21 @@ +package gorocksdb + +import "C" + +func NewMockMergeOperator(fm func(key, existingValue []byte, operands [][]byte) ([]byte, bool), pm func(key, leftOperand, rightOperand []byte) ([]byte, bool)) MergeOperator { + return &mockMergeOperator{fm, pm} +} + +type mockMergeOperator struct { + fullMerge func(key, existingValue []byte, operands [][]byte) ([]byte, bool) + partialMerge func(key, leftOperand, rightOperand []byte) ([]byte, bool) +} + +func (m *mockMergeOperator) Name() string { return "gorocksdb.test" } +func (m *mockMergeOperator) CName() *C.char { return C.CString("gorocksdb.test") } +func (m *mockMergeOperator) FullMerge(key, existingValue []byte, operands [][]byte) ([]byte, bool) { + return m.fullMerge(key, existingValue, operands) +} +func (m *mockMergeOperator) PartialMerge(key, leftOperand, rightOperand []byte) ([]byte, bool) { + return m.partialMerge(key, leftOperand, rightOperand) +} diff --git a/slice_transform.go b/slice_transform.go index 0505df2a..890b5928 100644 --- a/slice_transform.go +++ b/slice_transform.go @@ -16,6 +16,7 @@ type SliceTransform interface { // Return the name of this transformation. Name() string + CName() *C.char } // NewFixedPrefixTransform creates a new fixed prefix transform. @@ -25,17 +26,19 @@ func NewFixedPrefixTransform(prefixLen int) SliceTransform { // NewNativeSliceTransform creates a SliceTransform object. func NewNativeSliceTransform(c *C.rocksdb_slicetransform_t) SliceTransform { - return nativeSliceTransform{c} + return nativeSliceTransform{c, C.CString("")} } type nativeSliceTransform struct { - c *C.rocksdb_slicetransform_t + c *C.rocksdb_slicetransform_t + cname *C.char } func (st nativeSliceTransform) Transform(src []byte) []byte { return nil } func (st nativeSliceTransform) InDomain(src []byte) bool { return false } func (st nativeSliceTransform) InRange(src []byte) bool { return false } func (st nativeSliceTransform) Name() string { return "" } +func (st nativeSliceTransform) CName() *C.char { return st.cname } // Hold references to slice transforms. var sliceTransforms = NewCOWList() @@ -68,5 +71,5 @@ func gorocksdb_slicetransform_in_range(idx int, cKey *C.char, cKeyLen C.size_t) //export gorocksdb_slicetransform_name func gorocksdb_slicetransform_name(idx int) *C.char { - return stringToChar(sliceTransforms.Get(idx).(SliceTransform).Name()) + return sliceTransforms.Get(idx).(SliceTransform).CName() } diff --git a/slice_transform_test.go b/slice_transform_test.go index 1c551183..298e65cb 100644 --- a/slice_transform_test.go +++ b/slice_transform_test.go @@ -8,7 +8,7 @@ import ( func TestSliceTransform(t *testing.T) { db := newTestDB(t, "TestSliceTransform", func(opts *Options) { - opts.SetPrefixExtractor(&testSliceTransform{}) + opts.SetPrefixExtractor(NewMockSliceTransform()) }) defer db.Close() @@ -34,12 +34,3 @@ func TestFixedPrefixTransformOpen(t *testing.T) { }) defer db.Close() } - -type testSliceTransform struct { - initiated bool -} - -func (st *testSliceTransform) Name() string { return "gorocksdb.test" } -func (st *testSliceTransform) Transform(src []byte) []byte { return src[0:3] } -func (st *testSliceTransform) InDomain(src []byte) bool { return len(src) >= 3 } -func (st *testSliceTransform) InRange(src []byte) bool { return len(src) == 3 } diff --git a/slice_transform_test_mockstub.go b/slice_transform_test_mockstub.go new file mode 100644 index 00000000..b92c0cfc --- /dev/null +++ b/slice_transform_test_mockstub.go @@ -0,0 +1,17 @@ +package gorocksdb + +import "C" + +func NewMockSliceTransform() SliceTransform { + return &mockSliceTransform{} +} + +type mockSliceTransform struct { + initiated bool +} + +func (st *mockSliceTransform) Name() string { return "gorocksdb.test" } +func (st *mockSliceTransform) CName() *C.char { return C.CString("gorocksdb.test") } +func (st *mockSliceTransform) Transform(src []byte) []byte { return src[0:3] } +func (st *mockSliceTransform) InDomain(src []byte) bool { return len(src) >= 3 } +func (st *mockSliceTransform) InRange(src []byte) bool { return len(src) == 3 } diff --git a/util.go b/util.go index 9c373306..236f3fea 100644 --- a/util.go +++ b/util.go @@ -51,12 +51,6 @@ func cByteSlice(b []byte) *C.char { return c } -// stringToChar returns *C.char from string. -func stringToChar(s string) *C.char { - ptrStr := (*reflect.StringHeader)(unsafe.Pointer(&s)) - return (*C.char)(unsafe.Pointer(ptrStr.Data)) -} - // charSlice converts a C array of *char to a []*C.char. func charSlice(data **C.char, len C.int) []*C.char { var value []*C.char