github.com/zuoyebang/bitalosdb@v1.1.1-0.20240516111551-79a8c4d8ce20/internal/mmap/mmap_test.go (about)

     1  // Copyright 2021 The Bitalosdb author(hustxrb@163.com) and other contributors.
     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 mmap
    16  
    17  import (
    18  	"bytes"
    19  	"io/ioutil"
    20  	"os"
    21  	"path/filepath"
    22  	"testing"
    23  )
    24  
    25  const testMmapFile = "hi.mmap"
    26  
    27  func TestMMap(t *testing.T) {
    28  	t.Log(os.Getpid())
    29  	m, e := Open(testMmapFile, 32)
    30  	if e != nil {
    31  		t.Error(e)
    32  	}
    33  
    34  	n := m.ReadInt64At(0)
    35  	t.Log("read", n)
    36  
    37  	n += 20
    38  	m.WriteInt64At(n, 0)
    39  	t.Log("read", m.ReadInt64At(0))
    40  
    41  	n = m.ReadInt64At(8)
    42  	t.Log("read", n)
    43  
    44  	n += 20
    45  	m.WriteInt64At(n, 8)
    46  	t.Log("read", m.ReadInt64At(8))
    47  
    48  	n = m.ReadInt64At(16)
    49  	t.Log("read", n)
    50  
    51  	n += 20
    52  	m.WriteInt64At(n, 16)
    53  	t.Log("read", m.ReadInt64At(16))
    54  
    55  	v := []byte("abcdefgh")
    56  	m.WriteAt(v, 24)
    57  	wv := m.ReadAt(24, 8)
    58  	t.Log("read", string(wv))
    59  	os.Remove(testMmapFile)
    60  }
    61  
    62  func TestReadMmap(t *testing.T) {
    63  	m, e := Open(testMmapFile, 24)
    64  	if e != nil {
    65  		t.Error(e)
    66  	}
    67  	n := m.ReadInt64At(0)
    68  	t.Log("read", n)
    69  	os.Remove(testMmapFile)
    70  }
    71  
    72  var testData = []byte("0123456789ABCDEF")
    73  var testPath = filepath.Join(os.TempDir(), "testdata")
    74  
    75  func init() {
    76  	f := openFile(os.O_RDWR | os.O_CREATE | os.O_TRUNC)
    77  	f.Write(testData)
    78  	f.Close()
    79  }
    80  
    81  func openFile(flags int) *os.File {
    82  	f, err := os.OpenFile(testPath, flags, 0644)
    83  	if err != nil {
    84  		panic(err.Error())
    85  	}
    86  	return f
    87  }
    88  
    89  func TestUnmap(t *testing.T) {
    90  	f := openFile(os.O_RDONLY)
    91  	defer f.Close()
    92  	m, err := Map(f, RDONLY, 0)
    93  	if err != nil {
    94  		t.Errorf("error mapping: %s", err)
    95  	}
    96  	if err := m.Unmap(); err != nil {
    97  		t.Errorf("error unmapping: %s", err)
    98  	}
    99  }
   100  
   101  func TestReadWrite(t *testing.T) {
   102  	f := openFile(os.O_RDWR)
   103  	defer f.Close()
   104  	m, err := Map(f, RDWR, 0)
   105  	if err != nil {
   106  		t.Errorf("error mapping: %s", err)
   107  	}
   108  	defer m.Unmap()
   109  	if !bytes.Equal(testData, m) {
   110  		t.Errorf("mmap != testData: %q, %q", m, testData)
   111  	}
   112  
   113  	m[9] = 'X'
   114  	m.Flush()
   115  
   116  	fileData, err := ioutil.ReadAll(f)
   117  	if err != nil {
   118  		t.Errorf("error reading file: %s", err)
   119  	}
   120  	if !bytes.Equal(fileData, []byte("012345678XABCDEF")) {
   121  		t.Errorf("file wasn't modified")
   122  	}
   123  
   124  	// leave things how we found them
   125  	m[9] = '9'
   126  	m.Flush()
   127  }
   128  
   129  func TestProtFlagsAndErr(t *testing.T) {
   130  	f := openFile(os.O_RDONLY)
   131  	defer f.Close()
   132  	if _, err := Map(f, RDWR, 0); err == nil {
   133  		t.Errorf("expected error")
   134  	}
   135  }
   136  
   137  func TestFlags(t *testing.T) {
   138  	f := openFile(os.O_RDWR)
   139  	defer f.Close()
   140  	m, err := Map(f, COPY, 0)
   141  	if err != nil {
   142  		t.Errorf("error mapping: %s", err)
   143  	}
   144  	defer m.Unmap()
   145  
   146  	m[9] = 'X'
   147  	m.Flush()
   148  
   149  	fileData, err := ioutil.ReadAll(f)
   150  	if err != nil {
   151  		t.Errorf("error reading file: %s", err)
   152  	}
   153  	if !bytes.Equal(fileData, testData) {
   154  		t.Errorf("file was modified")
   155  	}
   156  }
   157  
   158  // Test that we can map files from non-0 offsets
   159  // The page size on most Unixes is 4KB, but on Windows it's 64KB
   160  func TestNonZeroOffset(t *testing.T) {
   161  	const pageSize = 65536
   162  
   163  	// Create a 2-page sized file
   164  	bigFilePath := filepath.Join(os.TempDir(), "nonzero")
   165  	fileobj, err := os.OpenFile(bigFilePath, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644)
   166  	if err != nil {
   167  		panic(err.Error())
   168  	}
   169  
   170  	bigData := make([]byte, 2*pageSize, 2*pageSize)
   171  	fileobj.Write(bigData)
   172  	fileobj.Close()
   173  
   174  	// Map the first page by itself
   175  	fileobj, err = os.OpenFile(bigFilePath, os.O_RDONLY, 0)
   176  	if err != nil {
   177  		panic(err.Error())
   178  	}
   179  	m, err := MapRegion(fileobj, pageSize, RDONLY, 0, 0)
   180  	if err != nil {
   181  		t.Errorf("error mapping file: %s", err)
   182  	}
   183  	m.Unmap()
   184  	fileobj.Close()
   185  
   186  	// Map the second page by itself
   187  	fileobj, err = os.OpenFile(bigFilePath, os.O_RDONLY, 0)
   188  	if err != nil {
   189  		panic(err.Error())
   190  	}
   191  	m, err = MapRegion(fileobj, pageSize, RDONLY, 0, pageSize)
   192  	if err != nil {
   193  		t.Errorf("error mapping file: %s", err)
   194  	}
   195  	err = m.Unmap()
   196  	if err != nil {
   197  		t.Error(err)
   198  	}
   199  
   200  	m, err = MapRegion(fileobj, pageSize, RDONLY, 0, 1)
   201  	if err == nil {
   202  		t.Error("expect error because offset is not multiple of page size")
   203  	}
   204  
   205  	fileobj.Close()
   206  }
   207  
   208  func TestAnonymousMapping(t *testing.T) {
   209  	const size = 4 * 1024
   210  
   211  	// Make an anonymous region
   212  	mem, err := MapRegion(nil, size, RDWR, ANON, 0)
   213  	if err != nil {
   214  		t.Fatalf("failed to allocate memory for buffer: %v", err)
   215  	}
   216  
   217  	// Check memory writable
   218  	for i := 0; i < size; i++ {
   219  		mem[i] = 0x55
   220  	}
   221  
   222  	// And unmap it
   223  	err = mem.Unmap()
   224  	if err != nil {
   225  		t.Fatalf("failed to unmap memory for buffer: %v", err)
   226  	}
   227  }