| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477 |
- package needle_map
- import (
- "fmt"
- "math/rand"
- "reflect"
- "testing"
- "github.com/seaweedfs/seaweedfs/weed/storage/types"
- )
- func TestSegmentBsearchKey(t *testing.T) {
- testSegment := &CompactMapSegment{
- list: []CompactNeedleValue{
- CompactNeedleValue{key: 10},
- CompactNeedleValue{key: 20},
- CompactNeedleValue{key: 21},
- CompactNeedleValue{key: 26},
- CompactNeedleValue{key: 30},
- },
- firstKey: 10,
- lastKey: 30,
- }
- testCases := []struct {
- name string
- cs *CompactMapSegment
- key types.NeedleId
- wantIndex int
- wantFound bool
- }{
- {
- name: "empty segment",
- cs: newCompactMapSegment(0),
- key: 123,
- wantIndex: 0,
- wantFound: false,
- },
- {
- name: "new key, insert at beggining",
- cs: testSegment,
- key: 5,
- wantIndex: 0,
- wantFound: false,
- },
- {
- name: "new key, insert at end",
- cs: testSegment,
- key: 100,
- wantIndex: 5,
- wantFound: false,
- },
- {
- name: "new key, insert second",
- cs: testSegment,
- key: 12,
- wantIndex: 1,
- wantFound: false,
- },
- {
- name: "new key, insert in middle",
- cs: testSegment,
- key: 23,
- wantIndex: 3,
- wantFound: false,
- },
- {
- name: "key #1",
- cs: testSegment,
- key: 10,
- wantIndex: 0,
- wantFound: true,
- },
- {
- name: "key #2",
- cs: testSegment,
- key: 20,
- wantIndex: 1,
- wantFound: true,
- },
- {
- name: "key #3",
- cs: testSegment,
- key: 21,
- wantIndex: 2,
- wantFound: true,
- },
- {
- name: "key #4",
- cs: testSegment,
- key: 26,
- wantIndex: 3,
- wantFound: true,
- },
- {
- name: "key #5",
- cs: testSegment,
- key: 30,
- wantIndex: 4,
- wantFound: true,
- },
- }
- for _, tc := range testCases {
- t.Run(tc.name, func(t *testing.T) {
- index, found := tc.cs.bsearchKey(tc.key)
- if got, want := index, tc.wantIndex; got != want {
- t.Errorf("expected %v, got %v", want, got)
- }
- if got, want := found, tc.wantFound; got != want {
- t.Errorf("expected %v, got %v", want, got)
- }
- })
- }
- }
- func TestSegmentSet(t *testing.T) {
- testSegment := &CompactMapSegment{
- list: []CompactNeedleValue{
- CompactNeedleValue{key: 10, offset: OffsetToCompact(types.Uint32ToOffset(0)), size: 100},
- CompactNeedleValue{key: 20, offset: OffsetToCompact(types.Uint32ToOffset(100)), size: 200},
- CompactNeedleValue{key: 30, offset: OffsetToCompact(types.Uint32ToOffset(300)), size: 300},
- },
- firstKey: 10,
- lastKey: 30,
- }
- if got, want := testSegment.len(), 3; got != want {
- t.Errorf("got starting size %d, want %d", got, want)
- }
- if got, want := testSegment.cap(), 3; got != want {
- t.Errorf("got starting capacity %d, want %d", got, want)
- }
- testSets := []struct {
- name string
- key types.NeedleId
- offset types.Offset
- size types.Size
- wantOffset types.Offset
- wantSize types.Size
- }{
- {
- name: "insert at beggining",
- key: 5, offset: types.Uint32ToOffset(1000), size: 123,
- wantOffset: types.Uint32ToOffset(0), wantSize: 0,
- },
- {
- name: "insert at end",
- key: 51, offset: types.Uint32ToOffset(7000), size: 456,
- wantOffset: types.Uint32ToOffset(0), wantSize: 0,
- },
- {
- name: "insert in middle",
- key: 25, offset: types.Uint32ToOffset(8000), size: 789,
- wantOffset: types.Uint32ToOffset(0), wantSize: 0,
- },
- {
- name: "update existing",
- key: 30, offset: types.Uint32ToOffset(9000), size: 999,
- wantOffset: types.Uint32ToOffset(300), wantSize: 300,
- },
- }
- for _, ts := range testSets {
- offset, size := testSegment.set(ts.key, ts.offset, ts.size)
- if offset != ts.wantOffset {
- t.Errorf("%s: got offset %v, want %v", ts.name, offset, ts.wantOffset)
- }
- if size != ts.wantSize {
- t.Errorf("%s: got size %v, want %v", ts.name, size, ts.wantSize)
- }
- }
- wantSegment := &CompactMapSegment{
- list: []CompactNeedleValue{
- CompactNeedleValue{key: 5, offset: OffsetToCompact(types.Uint32ToOffset(1000)), size: 123},
- CompactNeedleValue{key: 10, offset: OffsetToCompact(types.Uint32ToOffset(0)), size: 100},
- CompactNeedleValue{key: 20, offset: OffsetToCompact(types.Uint32ToOffset(100)), size: 200},
- CompactNeedleValue{key: 25, offset: OffsetToCompact(types.Uint32ToOffset(8000)), size: 789},
- CompactNeedleValue{key: 30, offset: OffsetToCompact(types.Uint32ToOffset(9000)), size: 999},
- CompactNeedleValue{key: 51, offset: OffsetToCompact(types.Uint32ToOffset(7000)), size: 456},
- },
- firstKey: 5,
- lastKey: 51,
- }
- if !reflect.DeepEqual(testSegment, wantSegment) {
- t.Errorf("got result segment %v, want %v", testSegment, wantSegment)
- }
- if got, want := testSegment.len(), 6; got != want {
- t.Errorf("got result size %d, want %d", got, want)
- }
- if got, want := testSegment.cap(), 6; got != want {
- t.Errorf("got result capacity %d, want %d", got, want)
- }
- }
- func TestSegmentSetOrdering(t *testing.T) {
- keys := []types.NeedleId{}
- for i := 0; i < SegmentChunkSize; i++ {
- keys = append(keys, types.NeedleId(i))
- }
- r := rand.New(rand.NewSource(123456789))
- r.Shuffle(len(keys), func(i, j int) { keys[i], keys[j] = keys[j], keys[i] })
- cs := newCompactMapSegment(0)
- for _, k := range keys {
- _, _ = cs.set(k, types.Uint32ToOffset(123), 456)
- }
- if got, want := cs.len(), SegmentChunkSize; got != want {
- t.Errorf("expected size %d, got %d", want, got)
- }
- for i := 1; i < cs.len(); i++ {
- if ka, kb := cs.list[i-1].key, cs.list[i].key; ka >= kb {
- t.Errorf("found out of order entries at (%d, %d) = (%d, %d)", i-1, i, ka, kb)
- }
- }
- }
- func TestSegmentGet(t *testing.T) {
- testSegment := &CompactMapSegment{
- list: []CompactNeedleValue{
- CompactNeedleValue{key: 10, offset: OffsetToCompact(types.Uint32ToOffset(0)), size: 100},
- CompactNeedleValue{key: 20, offset: OffsetToCompact(types.Uint32ToOffset(100)), size: 200},
- CompactNeedleValue{key: 30, offset: OffsetToCompact(types.Uint32ToOffset(300)), size: 300},
- },
- firstKey: 10,
- lastKey: 30,
- }
- testCases := []struct {
- name string
- key types.NeedleId
- wantValue *CompactNeedleValue
- wantFound bool
- }{
- {
- name: "invalid key",
- key: 99,
- wantValue: nil,
- wantFound: false,
- },
- {
- name: "key #1",
- key: 10,
- wantValue: &testSegment.list[0],
- wantFound: true,
- },
- {
- name: "key #2",
- key: 20,
- wantValue: &testSegment.list[1],
- wantFound: true,
- },
- {
- name: "key #3",
- key: 30,
- wantValue: &testSegment.list[2],
- wantFound: true,
- },
- }
- for _, tc := range testCases {
- t.Run(tc.name, func(t *testing.T) {
- value, found := testSegment.get(tc.key)
- if got, want := value, tc.wantValue; got != want {
- t.Errorf("got %v, want %v", got, want)
- }
- if got, want := found, tc.wantFound; got != want {
- t.Errorf("got %v, want %v", got, want)
- }
- })
- }
- }
- func TestSegmentDelete(t *testing.T) {
- testSegment := &CompactMapSegment{
- list: []CompactNeedleValue{
- CompactNeedleValue{key: 10, offset: OffsetToCompact(types.Uint32ToOffset(0)), size: 100},
- CompactNeedleValue{key: 20, offset: OffsetToCompact(types.Uint32ToOffset(100)), size: 200},
- CompactNeedleValue{key: 30, offset: OffsetToCompact(types.Uint32ToOffset(300)), size: 300},
- CompactNeedleValue{key: 40, offset: OffsetToCompact(types.Uint32ToOffset(600)), size: 400},
- },
- firstKey: 10,
- lastKey: 40,
- }
- testDeletes := []struct {
- name string
- key types.NeedleId
- want types.Size
- }{
- {
- name: "invalid key",
- key: 99,
- want: 0,
- },
- {
- name: "delete key #2",
- key: 20,
- want: 200,
- },
- {
- name: "delete key #4",
- key: 40,
- want: 400,
- },
- }
- for _, td := range testDeletes {
- size := testSegment.delete(td.key)
- if got, want := size, td.want; got != want {
- t.Errorf("%s: got %v, want %v", td.name, got, want)
- }
- }
- wantSegment := &CompactMapSegment{
- list: []CompactNeedleValue{
- CompactNeedleValue{key: 10, offset: OffsetToCompact(types.Uint32ToOffset(0)), size: 100},
- CompactNeedleValue{key: 20, offset: OffsetToCompact(types.Uint32ToOffset(100)), size: -200},
- CompactNeedleValue{key: 30, offset: OffsetToCompact(types.Uint32ToOffset(300)), size: 300},
- CompactNeedleValue{key: 40, offset: OffsetToCompact(types.Uint32ToOffset(600)), size: -400},
- },
- firstKey: 10,
- lastKey: 40,
- }
- if !reflect.DeepEqual(testSegment, wantSegment) {
- t.Errorf("got result segment %v, want %v", testSegment, wantSegment)
- }
- }
- func TestSegmentForKey(t *testing.T) {
- testMap := NewCompactMap()
- tests := []struct {
- name string
- key types.NeedleId
- want *CompactMapSegment
- }{
- {
- name: "first segment",
- key: 12,
- want: &CompactMapSegment{
- list: []CompactNeedleValue{},
- chunk: 0,
- firstKey: MaxCompactKey,
- lastKey: 0,
- },
- },
- {
- name: "second segment, gapless",
- key: SegmentChunkSize + 34,
- want: &CompactMapSegment{
- list: []CompactNeedleValue{},
- chunk: 1,
- firstKey: MaxCompactKey,
- lastKey: 0,
- },
- },
- {
- name: "gapped segment",
- key: (5 * SegmentChunkSize) + 56,
- want: &CompactMapSegment{
- list: []CompactNeedleValue{},
- chunk: 5,
- firstKey: MaxCompactKey,
- lastKey: 0,
- },
- },
- }
- for _, tc := range tests {
- t.Run(tc.name, func(t *testing.T) {
- cs := testMap.segmentForKey(tc.key)
- if !reflect.DeepEqual(cs, tc.want) {
- t.Errorf("got segment %v, want %v", cs, tc.want)
- }
- })
- }
- wantMap := &CompactMap{
- segments: map[Chunk]*CompactMapSegment{
- 0: &CompactMapSegment{
- list: []CompactNeedleValue{},
- chunk: 0,
- firstKey: MaxCompactKey,
- lastKey: 0,
- },
- 1: &CompactMapSegment{
- list: []CompactNeedleValue{},
- chunk: 1,
- firstKey: MaxCompactKey,
- lastKey: 0,
- },
- 5: &CompactMapSegment{
- list: []CompactNeedleValue{},
- chunk: 5,
- firstKey: MaxCompactKey,
- lastKey: 0,
- },
- },
- }
- if !reflect.DeepEqual(testMap, wantMap) {
- t.Errorf("got map %v, want %v", testMap, wantMap)
- }
- }
- func TestAscendingVisit(t *testing.T) {
- cm := NewCompactMap()
- for _, nid := range []types.NeedleId{20, 7, 40000, 300000, 0, 100, 500, 10000, 200000} {
- cm.Set(nid, types.Uint32ToOffset(123), 456)
- }
- got := []NeedleValue{}
- err := cm.AscendingVisit(func(nv NeedleValue) error {
- got = append(got, nv)
- return nil
- })
- if err != nil {
- t.Errorf("got error %v, expected none", err)
- }
- want := []NeedleValue{
- NeedleValue{Key: 0, Offset: types.Uint32ToOffset(123), Size: 456},
- NeedleValue{Key: 7, Offset: types.Uint32ToOffset(123), Size: 456},
- NeedleValue{Key: 20, Offset: types.Uint32ToOffset(123), Size: 456},
- NeedleValue{Key: 100, Offset: types.Uint32ToOffset(123), Size: 456},
- NeedleValue{Key: 500, Offset: types.Uint32ToOffset(123), Size: 456},
- NeedleValue{Key: 10000, Offset: types.Uint32ToOffset(123), Size: 456},
- NeedleValue{Key: 40000, Offset: types.Uint32ToOffset(123), Size: 456},
- NeedleValue{Key: 200000, Offset: types.Uint32ToOffset(123), Size: 456},
- NeedleValue{Key: 300000, Offset: types.Uint32ToOffset(123), Size: 456},
- }
- if !reflect.DeepEqual(got, want) {
- t.Errorf("got values %v, want %v", got, want)
- }
- }
- func TestRandomInsert(t *testing.T) {
- count := 8 * SegmentChunkSize
- keys := []types.NeedleId{}
- for i := 0; i < count; i++ {
- keys = append(keys, types.NeedleId(i))
- }
- r := rand.New(rand.NewSource(123456789))
- r.Shuffle(len(keys), func(i, j int) { keys[i], keys[j] = keys[j], keys[i] })
- cm := NewCompactMap()
- for _, k := range keys {
- _, _ = cm.Set(k, types.Uint32ToOffset(123), 456)
- }
- if got, want := cm.Len(), count; got != want {
- t.Errorf("expected size %d, got %d", want, got)
- }
- last := -1
- err := cm.AscendingVisit(func(nv NeedleValue) error {
- key := int(nv.Key)
- if key <= last {
- return fmt.Errorf("found out of order entries (%d vs %d)", key, last)
- }
- last = key
- return nil
- })
- if err != nil {
- t.Errorf("got error %v, expected none", err)
- }
- // Given that we've written a integer multiple of SegmentChunkSize, all
- // segments should be fully utilized and capacity-adjusted.
- if l, c := cm.Len(), cm.Cap(); l != c {
- t.Errorf("map length (%d) doesn't match capacity (%d)", l, c)
- }
- }
|