github.com/NVIDIA/aistore@v1.3.23-0.20240517131212-7df6609be51d/tools/readers/readers_test.go (about)

     1  // Package readers provides implementation for common reader types
     2  /*
     3   * Copyright (c) 2018-2024, NVIDIA CORPORATION. All rights reserved.
     4   */
     5  package readers_test
     6  
     7  import (
     8  	"io"
     9  	"os"
    10  	"path"
    11  	"reflect"
    12  	"testing"
    13  
    14  	"github.com/NVIDIA/aistore/cmn/cos"
    15  	"github.com/NVIDIA/aistore/memsys"
    16  	"github.com/NVIDIA/aistore/tools/readers"
    17  	"github.com/NVIDIA/aistore/tools/tassert"
    18  )
    19  
    20  const mmName = "readers_test"
    21  
    22  func TestFileReader(t *testing.T) {
    23  	r, err := readers.NewRandFile("/tmp", "seek", 10240, cos.ChecksumNone)
    24  	if err != nil {
    25  		t.Fatal("Failed to create file reader", err)
    26  	}
    27  	tassert.CheckFatal(t, r.Close())
    28  }
    29  
    30  func testReaderBasic(t *testing.T, r readers.Reader, size int64) {
    31  	_, err := r.Seek(0, io.SeekStart)
    32  	if err != nil {
    33  		t.Fatal("Failed to seek", err)
    34  	}
    35  
    36  	data := make([]byte, size)
    37  	n, err := r.Read(data)
    38  	if err != nil || int64(n) != size {
    39  		t.Fatal("Failed to read all data", n, err)
    40  	}
    41  
    42  	{
    43  		// Seek from start and read should return the correct data
    44  		n, err := r.Seek(100, io.SeekStart)
    45  		if err != nil || n != 100 {
    46  			t.Fatal("Failed to seek", n, err)
    47  		}
    48  
    49  		buf := make([]byte, 20)
    50  		m, err := r.Read(buf)
    51  		if err != nil || m != 20 {
    52  			t.Fatal("Failed to read after seek", n, err)
    53  		}
    54  
    55  		if !reflect.DeepEqual(buf, data[100:120]) {
    56  			t.Fatal("Failed to match data after seek and read", buf, data[100:120])
    57  		}
    58  
    59  		r.Seek(0, io.SeekStart)
    60  	}
    61  
    62  	{
    63  		// Seek from end and read should return the correct data
    64  		_, err := r.Seek(-40, io.SeekEnd)
    65  		if err != nil {
    66  			t.Fatal("Failed to seek", err)
    67  		}
    68  
    69  		buf := make([]byte, 20)
    70  		m, err := r.Read(buf)
    71  		if err != nil || m != 20 {
    72  			t.Fatal("Failed to read after seek", n, err)
    73  		}
    74  
    75  		if !reflect.DeepEqual(buf, data[size-40:size-20]) {
    76  			t.Fatal("Failed to match data after seek and read", buf, data[size-40:size-20])
    77  		}
    78  
    79  		r.Seek(0, io.SeekStart)
    80  	}
    81  
    82  	{
    83  		// Seek from end and read should return the correct data
    84  		_, err := r.Seek(-40, io.SeekEnd)
    85  		if err != nil {
    86  			t.Fatal("Failed to seek", err)
    87  		}
    88  
    89  		buf := make([]byte, 20)
    90  		m, err := r.Read(buf)
    91  		if err != nil || m != 20 {
    92  			t.Fatal("Failed to read after seek", n, err)
    93  		}
    94  
    95  		if !reflect.DeepEqual(buf, data[size-40:size-20]) {
    96  			t.Fatal("Failed to match data after seek and read", buf, data[size-40:size-20])
    97  		}
    98  
    99  		r.Seek(0, io.SeekStart)
   100  	}
   101  }
   102  
   103  // NOTE: These are testcases that fail when running on SGReader.
   104  func testReaderAdv(t *testing.T, r readers.Reader, size int64) {
   105  	buf := make([]byte, size)
   106  	_, err := r.Seek(0, io.SeekStart)
   107  	if err != nil {
   108  		t.Fatal("Failed to seek", err)
   109  	}
   110  
   111  	data := make([]byte, size)
   112  	n, err := r.Read(data)
   113  	if err != nil || int64(n) != size {
   114  		t.Fatal("Failed to read all data", n, err)
   115  	}
   116  
   117  	{
   118  		// Seek pass EOF
   119  		_, err := r.Seek(size+10, io.SeekStart)
   120  		if err != nil {
   121  			t.Fatal("Failed to seek pass EOF", err)
   122  		}
   123  
   124  		buf := make([]byte, 20)
   125  		_, err = r.Read(buf)
   126  		if err == nil {
   127  			t.Fatal("Failed to return error while reading pass EOF")
   128  		}
   129  
   130  		r.Seek(0, io.SeekStart)
   131  	}
   132  
   133  	{
   134  		// Seek relative and read should return the correct data
   135  		_, err := r.Seek(size-40, io.SeekStart)
   136  		if err != nil {
   137  			t.Fatal("Failed to seek", err)
   138  		}
   139  
   140  		n, err := r.Seek(-20, io.SeekCurrent)
   141  		if err != nil || n != size-60 {
   142  			t.Fatal("Failed to seek", n, err)
   143  		}
   144  
   145  		buf := make([]byte, 20)
   146  		m, err := r.Read(buf)
   147  		if err != nil || m != 20 {
   148  			t.Fatal("Failed to read after seek", n, err)
   149  		}
   150  
   151  		if !reflect.DeepEqual(buf, data[size-60:size-40]) {
   152  			t.Fatal("Failed to match data after seek and read", buf, data[size-60:size-40])
   153  		}
   154  
   155  		r.Seek(0, io.SeekStart)
   156  	}
   157  
   158  	{
   159  		// Read return the correct number of data when there are enough data
   160  		m, err := r.Seek(0, io.SeekStart)
   161  		if err != nil {
   162  			t.Fatal("Failed to seek", err)
   163  		}
   164  
   165  		if m != 0 {
   166  			t.Fatal("Failed to seek to begin", m)
   167  		}
   168  
   169  		n, err := r.Read(buf[:size-20])
   170  		if err != nil {
   171  			t.Fatal("Failed to seek", err)
   172  		}
   173  
   174  		if int64(n) != size-20 {
   175  			t.Fatalf("Failed to seek, expected %d, actual %d", size-20, n)
   176  		}
   177  
   178  		n, err = r.Read(buf[:8])
   179  		if err != nil || n != 8 {
   180  			t.Fatal("Failed to read", n, err)
   181  		}
   182  
   183  		n, err = r.Read(buf[:8])
   184  		if err != nil || n != 8 {
   185  			t.Fatal("Failed to read", n, err)
   186  		}
   187  
   188  		n, err = r.Read(buf[:8])
   189  		if err != nil || n != 4 {
   190  			t.Fatal("Failed to read when there is less data", n, err)
   191  		}
   192  
   193  		_, err = r.Read(buf)
   194  		if err != io.EOF {
   195  			t.Fatal("Failed to read when it is EOF", err)
   196  		}
   197  	}
   198  
   199  	{
   200  		// Read return the correct number of data when there are enough data
   201  		o, err := r.Seek(-20, io.SeekEnd)
   202  		if err != nil {
   203  			t.Fatal("Failed to seek", err)
   204  		}
   205  		if o != size-20 {
   206  			t.Fatalf("Failed to seek, offset expected %d, actual %d", size-20, o)
   207  		}
   208  
   209  		buf := make([]byte, 8)
   210  		n, err := r.Read(buf)
   211  		if err != nil || n != 8 {
   212  			t.Fatal("Failed to read", n, err)
   213  		}
   214  
   215  		n, err = r.Read(buf)
   216  		if err != nil || n != 8 {
   217  			t.Fatal("Failed to read", n, err)
   218  		}
   219  
   220  		n, err = r.Read(buf)
   221  		if err != nil || n != 4 {
   222  			t.Fatal("Failed to read when there is less data", n, err)
   223  		}
   224  
   225  		_, err = r.Read(buf)
   226  		if err != io.EOF {
   227  			t.Fatal("Failed to read when it is EOF", err)
   228  		}
   229  	}
   230  }
   231  
   232  func TestRandReader(t *testing.T) {
   233  	size := int64(1024)
   234  	r, err := readers.NewRand(size, cos.ChecksumXXHash)
   235  	if err != nil {
   236  		t.Fatal(err)
   237  	}
   238  	testReaderBasic(t, r, size)
   239  	testReaderAdv(t, r, size)
   240  	r.Close()
   241  }
   242  
   243  func TestSGReader(t *testing.T) {
   244  	mmsa, _ := memsys.NewMMSA(mmName, false)
   245  	defer mmsa.Terminate(false)
   246  	{
   247  		// Basic read
   248  		size := int64(1024)
   249  		sgl := mmsa.NewSGL(size)
   250  		defer sgl.Free()
   251  
   252  		r, err := readers.NewSG(sgl, size, cos.ChecksumXXHash)
   253  		if err != nil {
   254  			t.Fatal(err)
   255  		}
   256  
   257  		buf := make([]byte, size)
   258  		n, err := r.Read(buf[:512])
   259  		if err != nil && err != io.EOF {
   260  			t.Fatal(err)
   261  		}
   262  
   263  		if n != 512 {
   264  			t.Fatalf("Read returned wrong number of bytes, expected = %d, actual = %d", 512, n)
   265  		}
   266  
   267  		n, err = r.Read(buf)
   268  		if err != nil && err != io.EOF {
   269  			t.Fatal(err)
   270  		}
   271  
   272  		if n != 512 {
   273  			t.Fatalf("Read returned wrong number of bytes, expected = %d, actual = %d", 512, n)
   274  		}
   275  
   276  		r.Close()
   277  	}
   278  
   279  	{
   280  		size := int64(1024)
   281  		sgl := mmsa.NewSGL(size)
   282  		defer sgl.Free()
   283  
   284  		r, err := readers.NewSG(sgl, size, cos.ChecksumXXHash)
   285  		if err != nil {
   286  			t.Fatal(err)
   287  		}
   288  		testReaderBasic(t, r, size)
   289  		r.Close()
   290  	}
   291  }
   292  
   293  func BenchmarkFileReaderCreateWithHash1M(b *testing.B) {
   294  	filepath := "/tmp"
   295  	fn := "reader-test"
   296  
   297  	for range b.N {
   298  		r, err := readers.NewRandFile(filepath, fn, cos.MiB, cos.ChecksumXXHash)
   299  		if err != nil {
   300  			os.Remove(path.Join(filepath, fn))
   301  			b.Fatal(err)
   302  		}
   303  		if err := r.Close(); err != nil {
   304  			os.Remove(path.Join(filepath, fn))
   305  			b.Fatal(err)
   306  		}
   307  		os.Remove(path.Join(filepath, fn))
   308  	}
   309  }
   310  
   311  func BenchmarkRandReaderCreateWithHash1M(b *testing.B) {
   312  	for range b.N {
   313  		r, err := readers.NewRand(cos.MiB, cos.ChecksumXXHash)
   314  		r.Close()
   315  		if err != nil {
   316  			b.Fatal(err)
   317  		}
   318  	}
   319  }
   320  
   321  func BenchmarkSGReaderCreateWithHash1M(b *testing.B) {
   322  	mmsa, _ := memsys.NewMMSA(mmName, false)
   323  	sgl := mmsa.NewSGL(cos.MiB)
   324  	defer func() {
   325  		sgl.Free()
   326  		mmsa.Terminate(false)
   327  	}()
   328  
   329  	for range b.N {
   330  		sgl.Reset()
   331  		r, err := readers.NewSG(sgl, cos.MiB, cos.ChecksumXXHash)
   332  		r.Close()
   333  		if err != nil {
   334  			b.Fatal(err)
   335  		}
   336  	}
   337  }
   338  
   339  func BenchmarkFileReaderCreateNoHash1M(b *testing.B) {
   340  	filepath := "/tmp"
   341  	fn := "reader-test"
   342  
   343  	for range b.N {
   344  		r, err := readers.NewRandFile(filepath, fn, cos.MiB, cos.ChecksumNone)
   345  		if err != nil {
   346  			os.Remove(path.Join(filepath, fn))
   347  			b.Fatal(err)
   348  		}
   349  		if err := r.Close(); err != nil {
   350  			os.Remove(path.Join(filepath, fn))
   351  			b.Fatal(err)
   352  		}
   353  		os.Remove(path.Join(filepath, fn))
   354  	}
   355  }
   356  
   357  func BenchmarkRandReaderCreateNoHash1M(b *testing.B) {
   358  	for range b.N {
   359  		r, err := readers.NewRand(cos.MiB, cos.ChecksumNone)
   360  		r.Close()
   361  		if err != nil {
   362  			b.Fatal(err)
   363  		}
   364  	}
   365  }
   366  
   367  func BenchmarkSGReaderCreateNoHash1M(b *testing.B) {
   368  	mmsa, _ := memsys.NewMMSA(mmName, false)
   369  	sgl := mmsa.NewSGL(cos.MiB)
   370  	defer func() {
   371  		sgl.Free()
   372  		mmsa.Terminate(false)
   373  	}()
   374  
   375  	for range b.N {
   376  		sgl.Reset()
   377  		r, err := readers.NewSG(sgl, cos.MiB, cos.ChecksumNone)
   378  		r.Close()
   379  		if err != nil {
   380  			b.Fatal(err)
   381  		}
   382  	}
   383  }