github.com/outcaste-io/ristretto@v0.2.3/z/buffer_test.go (about) 1 /* 2 * Copyright 2020 Dgraph Labs, Inc. and Contributors 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package z 18 19 import ( 20 "bytes" 21 "encoding/binary" 22 "encoding/hex" 23 "fmt" 24 "math/rand" 25 "sort" 26 "testing" 27 "time" 28 29 "github.com/stretchr/testify/require" 30 ) 31 32 func TestBuffer(t *testing.T) { 33 rand.Seed(time.Now().Unix()) 34 const capacity = 512 35 buffers := newTestBuffers(t, capacity) 36 37 for _, buf := range buffers { 38 name := fmt.Sprintf("Using buffer type: %s", buf.bufType) 39 t.Run(name, func(t *testing.T) { 40 // This is just for verifying result 41 var bytesBuf bytes.Buffer 42 bytesBuf.Grow(capacity) 43 44 // Writer small []byte 45 var smallData [256]byte 46 rand.Read(smallData[:]) 47 var bigData [1024]byte 48 rand.Read(bigData[:]) 49 50 _, err := buf.Write(smallData[:]) 51 require.NoError(t, err, "unable to write data to page buffer") 52 _, err = buf.Write(bigData[:]) 53 require.NoError(t, err, "unable to write data to page buffer") 54 55 // Write data to bytesBuffer also, just to match result. 56 bytesBuf.Write(smallData[:]) 57 bytesBuf.Write(bigData[:]) 58 require.Equal(t, buf.Bytes(), bytesBuf.Bytes()) 59 }) 60 } 61 } 62 63 func TestBufferWrite(t *testing.T) { 64 rand.Seed(time.Now().Unix()) 65 const capacity = 32 66 buffers := newTestBuffers(t, capacity) 67 68 for _, buf := range buffers { 69 name := fmt.Sprintf("Using buffer type: %s", buf.bufType) 70 t.Run(name, func(t *testing.T) { 71 var data [128]byte 72 rand.Read(data[:]) 73 bytesBuf := new(bytes.Buffer) 74 75 end := 32 76 for i := 0; i < 3; i++ { 77 n, err := buf.Write(data[:end]) 78 require.NoError(t, err, "unable to write bytes to buffer") 79 require.Equal(t, n, end, "length of buffer and length written should be equal") 80 81 // append to bb also for testing. 82 bytesBuf.Write(data[:end]) 83 84 require.Equal(t, buf.Bytes(), bytesBuf.Bytes()) 85 end = end * 2 86 } 87 88 }) 89 } 90 } 91 92 func TestBufferAutoMmap(t *testing.T) { 93 buf := NewBuffer(1<<20, "test").WithAutoMmap(64<<20, "") 94 defer func() { require.NoError(t, buf.Release()) }() 95 96 N := 128 << 10 97 var wb [1024]byte 98 for i := 0; i < N; i++ { 99 rand.Read(wb[:]) 100 b := buf.SliceAllocate(len(wb)) 101 copy(b, wb[:]) 102 } 103 t.Logf("Buffer size: %d\n", buf.LenWithPadding()) 104 105 buf.SortSlice(func(l, r []byte) bool { 106 return bytes.Compare(l, r) < 0 107 }) 108 t.Logf("sort done\n") 109 110 var count int 111 var last []byte 112 buf.SliceIterate(func(slice []byte) error { 113 require.True(t, bytes.Compare(slice, last) >= 0) 114 last = append(last[:0], slice...) 115 count++ 116 return nil 117 }) 118 require.Equal(t, N, count) 119 } 120 121 func TestBufferSimpleSort(t *testing.T) { 122 bufs := newTestBuffers(t, 1<<20) 123 for _, buf := range bufs { 124 name := fmt.Sprintf("Using buffer type: %s", buf.bufType) 125 t.Run(name, func(t *testing.T) { 126 for i := 0; i < 25600; i++ { 127 b := buf.SliceAllocate(4) 128 binary.BigEndian.PutUint32(b, uint32(rand.Int31n(256000))) 129 } 130 buf.SortSlice(func(ls, rs []byte) bool { 131 left := binary.BigEndian.Uint32(ls) 132 right := binary.BigEndian.Uint32(rs) 133 return left < right 134 }) 135 var last uint32 136 var i int 137 buf.SliceIterate(func(slice []byte) error { 138 num := binary.BigEndian.Uint32(slice) 139 if num < last { 140 fmt.Printf("num: %d idx: %d last: %d\n", num, i, last) 141 } 142 i++ 143 require.GreaterOrEqual(t, num, last) 144 last = num 145 // fmt.Printf("Got number: %d\n", num) 146 return nil 147 }) 148 }) 149 } 150 } 151 152 func TestBufferSlice(t *testing.T) { 153 const capacity = 32 154 buffers := newTestBuffers(t, capacity) 155 156 for _, buf := range buffers { 157 name := fmt.Sprintf("Using buffer type: %s", buf.bufType) 158 t.Run(name, func(t *testing.T) { 159 count := 10000 160 exp := make([][]byte, 0, count) 161 162 // Create "count" number of slices. 163 for i := 0; i < count; i++ { 164 sz := 1 + rand.Intn(8) 165 testBuf := make([]byte, sz) 166 rand.Read(testBuf) 167 168 newSlice := buf.SliceAllocate(sz) 169 require.Equal(t, sz, copy(newSlice, testBuf)) 170 171 // Save testBuf for verification. 172 exp = append(exp, testBuf) 173 } 174 175 compare := func() { 176 i := 0 177 buf.SliceIterate(func(slice []byte) error { 178 // All the slices returned by the buffer should be equal to what we 179 // inserted earlier. 180 if !bytes.Equal(exp[i], slice) { 181 fmt.Printf("exp: %s got: %s\n", hex.Dump(exp[i]), hex.Dump(slice)) 182 t.Fail() 183 } 184 require.Equal(t, exp[i], slice) 185 i++ 186 return nil 187 }) 188 require.Equal(t, len(exp), i) 189 } 190 compare() // same order as inserted. 191 192 t.Logf("Sorting using sort.Slice\n") 193 sort.Slice(exp, func(i, j int) bool { 194 return bytes.Compare(exp[i], exp[j]) < 0 195 }) 196 t.Logf("Sorting using buf.SortSlice\n") 197 buf.SortSlice(func(a, b []byte) bool { 198 return bytes.Compare(a, b) < 0 199 }) 200 t.Logf("Done sorting\n") 201 compare() // same order after sort. 202 }) 203 } 204 } 205 206 func TestBufferSort(t *testing.T) { 207 const capacity = 32 208 bufs := newTestBuffers(t, capacity) 209 210 for _, buf := range bufs { 211 name := fmt.Sprintf("Using buffer type: %s", buf.bufType) 212 t.Run(name, func(t *testing.T) { 213 const N = 10000 214 215 for i := 0; i < N; i++ { 216 newSlice := buf.SliceAllocate(8) 217 uid := uint64(rand.Int63()) 218 binary.BigEndian.PutUint64(newSlice, uid) 219 } 220 221 test := func(start, end int) { 222 start = buf.StartOffset() + 12*start 223 end = buf.StartOffset() + 12*end 224 buf.SortSliceBetween(start, end, func(ls, rs []byte) bool { 225 lhs := binary.BigEndian.Uint64(ls) 226 rhs := binary.BigEndian.Uint64(rs) 227 return lhs < rhs 228 }) 229 230 slice, next := []byte{}, start 231 var last uint64 232 var count int 233 for next >= 0 && next < end { 234 slice, next = buf.Slice(next) 235 uid := binary.BigEndian.Uint64(slice) 236 require.GreaterOrEqual(t, uid, last) 237 last = uid 238 count++ 239 } 240 require.Equal(t, (end-start)/12, count) 241 } 242 for i := 10; i <= N; i += 10 { 243 test(i-10, i) 244 } 245 test(0, N) 246 }) 247 } 248 } 249 250 // Test that the APIs returns the expected offsets. 251 func TestBufferPadding(t *testing.T) { 252 bufs := newTestBuffers(t, 1<<10) 253 for _, buf := range bufs { 254 name := fmt.Sprintf("Using buffer type: %s", buf.bufType) 255 t.Run(name, func(t *testing.T) { 256 sz := rand.Int31n(100) 257 258 writeOffset := buf.AllocateOffset(int(sz)) 259 require.Equal(t, buf.StartOffset(), writeOffset) 260 261 b := make([]byte, sz) 262 rand.Read(b) 263 264 copy(buf.Bytes(), b) 265 data := buf.Data(buf.StartOffset()) 266 require.Equal(t, b, data[:sz]) 267 }) 268 } 269 } 270 271 func newTestBuffers(t *testing.T, capacity int) []*Buffer { 272 var bufs []*Buffer 273 274 buf := NewBuffer(capacity, "test") 275 bufs = append(bufs, buf) 276 277 buf, err := NewBufferTmp("", capacity) 278 require.NoError(t, err) 279 bufs = append(bufs, buf) 280 281 t.Cleanup(func() { 282 for _, buf := range bufs { 283 require.NoError(t, buf.Release()) 284 } 285 }) 286 287 return bufs 288 } 289 290 func TestSmallBuffer(t *testing.T) { 291 buf := NewBuffer(5, "test") 292 t.Cleanup(func() { 293 require.NoError(t, buf.Release()) 294 }) 295 // Write something to buffer so sort actually happens. 296 buf.WriteSlice([]byte("abc")) 297 // This test fails if the buffer has offset > currSz. 298 require.NotPanics(t, func() { 299 buf.SortSlice(func(left, right []byte) bool { 300 return true 301 }) 302 }) 303 }