github.com/matrixorigin/matrixone@v1.2.0/pkg/fileservice/file_with_checksum_test.go (about) 1 // Copyright 2022 Matrix Origin 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package fileservice 16 17 import ( 18 "bytes" 19 "context" 20 "crypto/rand" 21 "io" 22 "os" 23 "testing" 24 "testing/iotest" 25 26 "github.com/stretchr/testify/assert" 27 ) 28 29 func TestFileWithChecksumOffsets(t *testing.T) { 30 ctx := context.Background() 31 f := NewFileWithChecksum[*os.File](ctx, nil, 64, nil) 32 33 blockOffset, offsetInBlock := f.contentOffsetToBlockOffset(0) 34 assert.Equal(t, int64(0), blockOffset) 35 assert.Equal(t, int64(0), offsetInBlock) 36 37 blockOffset, offsetInBlock = f.contentOffsetToBlockOffset(1) 38 assert.Equal(t, int64(0), blockOffset) 39 assert.Equal(t, int64(1), offsetInBlock) 40 41 blockOffset, offsetInBlock = f.contentOffsetToBlockOffset(int64(f.blockContentSize)) 42 assert.Equal(t, int64(f.blockSize), blockOffset) 43 assert.Equal(t, int64(0), offsetInBlock) 44 45 blockOffset, offsetInBlock = f.contentOffsetToBlockOffset(int64(f.blockContentSize) + 1) 46 assert.Equal(t, int64(f.blockSize), blockOffset) 47 assert.Equal(t, int64(1), offsetInBlock) 48 49 blockOffset, offsetInBlock = f.contentOffsetToBlockOffset(int64(f.blockContentSize)*2 + 1) 50 assert.Equal(t, int64(f.blockSize*2), blockOffset) 51 assert.Equal(t, int64(1), offsetInBlock) 52 53 blockOffset, offsetInBlock = f.contentOffsetToBlockOffset(int64(f.blockContentSize)*3 + 1) 54 assert.Equal(t, int64(f.blockSize*3), blockOffset) 55 assert.Equal(t, int64(1), offsetInBlock) 56 } 57 58 func TestFileWithChecksum(t *testing.T) { 59 blockContentSize := 8 60 tempDir := t.TempDir() 61 62 testFileWithChecksum( 63 t, 64 blockContentSize, 65 func() FileLike { 66 f, err := os.CreateTemp(tempDir, "*") 67 assert.Nil(t, err) 68 t.Cleanup(func() { 69 f.Close() 70 }) 71 return f 72 }, 73 ) 74 } 75 76 func testFileWithChecksum( 77 t *testing.T, 78 blockContentSize int, 79 newUnderlying func() FileLike, 80 ) { 81 82 for i := 0; i < blockContentSize*4; i++ { 83 84 underlying := newUnderlying() 85 ctx := context.Background() 86 fileWithChecksum := NewFileWithChecksum(ctx, underlying, blockContentSize, nil) 87 88 check := func(data []byte) { 89 // check content 90 pos, err := fileWithChecksum.Seek(0, io.SeekStart) 91 assert.Nil(t, err) 92 assert.Equal(t, int64(0), pos) 93 content, err := io.ReadAll(fileWithChecksum) 94 assert.Nil(t, err) 95 assert.Equal(t, data, content) 96 97 // seek 98 n, err := fileWithChecksum.Seek(0, io.SeekEnd) 99 assert.Nil(t, err) 100 assert.Equal(t, int64(len(data)), n) 101 102 // iotest 103 pos, err = fileWithChecksum.Seek(0, io.SeekStart) 104 assert.Nil(t, err) 105 assert.Equal(t, int64(0), pos) 106 err = iotest.TestReader(fileWithChecksum, data) 107 if err != nil { 108 t.Logf("%s", err) 109 } 110 assert.Nil(t, err) 111 } 112 113 // random bytes 114 data := make([]byte, i) 115 _, err := rand.Read(data) 116 assert.Nil(t, err) 117 118 // write 119 n, err := fileWithChecksum.Write(data) 120 assert.Nil(t, err) 121 assert.Equal(t, i, n) 122 123 // underlying size 124 underlyingSize, err := underlying.Seek(0, io.SeekEnd) 125 assert.Nil(t, err) 126 expectedSize := len(data) / blockContentSize * (blockContentSize + _ChecksumSize) 127 mod := len(data) % blockContentSize 128 if mod != 0 { 129 expectedSize += _ChecksumSize + mod 130 } 131 assert.Equal(t, expectedSize, int(underlyingSize)) 132 133 check(data) 134 135 for j := 0; j < len(data); j++ { 136 137 // seek and write random bytes 138 _, err = rand.Read(data[j:]) 139 assert.Nil(t, err) 140 pos, err := fileWithChecksum.Seek(int64(j), io.SeekStart) 141 assert.Nil(t, err) 142 assert.Equal(t, int64(j), pos) 143 n, err = fileWithChecksum.Write(data[j:]) 144 assert.Nil(t, err) 145 assert.Equal(t, len(data[j:]), n) 146 147 // seek and read 148 pos, err = fileWithChecksum.Seek(int64(j), io.SeekStart) 149 assert.Nil(t, err) 150 assert.Equal(t, int64(j), pos) 151 content, err := io.ReadAll(fileWithChecksum) 152 assert.Nil(t, err) 153 assert.Equal(t, data[j:], content) 154 155 check(data) 156 157 } 158 159 } 160 } 161 162 func TestMultiLayerFileWithChecksum(t *testing.T) { 163 blockContentSize := 8 164 tempDir := t.TempDir() 165 166 testFileWithChecksum( 167 t, 168 blockContentSize, 169 func() FileLike { 170 f, err := os.CreateTemp(tempDir, "*") 171 assert.Nil(t, err) 172 t.Cleanup(func() { 173 f.Close() 174 }) 175 ctx := context.Background() 176 f2 := NewFileWithChecksum(ctx, f, blockContentSize, nil) 177 f3 := NewFileWithChecksum(ctx, f2, blockContentSize, nil) 178 f4 := NewFileWithChecksum(ctx, f3, blockContentSize, nil) 179 return f4 180 }, 181 ) 182 } 183 184 func BenchmarkFileWithChecksumRead(b *testing.B) { 185 ctx := context.Background() 186 187 dir := b.TempDir() 188 f, err := os.CreateTemp(dir, "*") 189 if err != nil { 190 b.Fatal(err) 191 } 192 defer f.Close() 193 194 f2 := NewFileWithChecksum(ctx, f, _BlockContentSize, nil) 195 _, err = f2.Write(bytes.Repeat([]byte("a"), 65536)) 196 if err != nil { 197 b.Fatal(err) 198 } 199 200 b.ResetTimer() 201 for i := 0; i < b.N; i++ { 202 _, err = f2.Seek(0, io.SeekStart) 203 if err != nil { 204 b.Fatal(err) 205 } 206 n, err := io.Copy(io.Discard, f2) 207 if err != nil { 208 b.Fatal(err) 209 } 210 if n != 65536 { 211 b.Fatal() 212 } 213 } 214 } 215 216 func BenchmarkFileWithChecksumWrite(b *testing.B) { 217 ctx := context.Background() 218 219 dir := b.TempDir() 220 f, err := os.CreateTemp(dir, "*") 221 if err != nil { 222 b.Fatal(err) 223 } 224 defer f.Close() 225 226 content := bytes.Repeat([]byte("a"), 65536) 227 f2 := NewFileWithChecksum(ctx, f, _BlockContentSize, nil) 228 _, err = f2.Write(content) 229 if err != nil { 230 b.Fatal(err) 231 } 232 233 b.ResetTimer() 234 for i := 0; i < b.N; i++ { 235 _, err = f2.Seek(0, io.SeekStart) 236 if err != nil { 237 b.Fatal(err) 238 } 239 n, err := f2.Write(content) 240 if err != nil { 241 b.Fatal(err) 242 } 243 if n != 65536 { 244 b.Fatal() 245 } 246 } 247 }