github.com/ledgerwatch/erigon-lib@v1.0.0/mmap/mmap_unix.go (about)

     1  //go:build !windows
     2  
     3  /*
     4     Copyright 2021 Erigon contributors
     5  
     6     Licensed under the Apache License, Version 2.0 (the "License");
     7     you may not use this file except in compliance with the License.
     8     You may obtain a copy of the License at
     9  
    10         http://www.apache.org/licenses/LICENSE-2.0
    11  
    12     Unless required by applicable law or agreed to in writing, software
    13     distributed under the License is distributed on an "AS IS" BASIS,
    14     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    15     See the License for the specific language governing permissions and
    16     limitations under the License.
    17  */
    18  
    19  package mmap
    20  
    21  import (
    22  	"errors"
    23  	"fmt"
    24  	"os"
    25  	"syscall"
    26  	"unsafe"
    27  
    28  	"golang.org/x/sys/unix"
    29  )
    30  
    31  const MaxMapSize = 0xFFFFFFFFFFFF
    32  
    33  // mmap memory maps a DB's data file.
    34  func MmapRw(f *os.File, size int) ([]byte, *[MaxMapSize]byte, error) {
    35  	// Map the data file to memory.
    36  	mmapHandle1, err := unix.Mmap(int(f.Fd()), 0, size, syscall.PROT_READ|syscall.PROT_WRITE, syscall.MAP_SHARED)
    37  	if err != nil {
    38  		return nil, nil, err
    39  	}
    40  
    41  	// Advise the kernel that the mmap is accessed randomly.
    42  	err = unix.Madvise(mmapHandle1, syscall.MADV_RANDOM)
    43  	if err != nil && !errors.Is(err, syscall.ENOSYS) {
    44  		// Ignore not implemented error in kernel because it still works.
    45  		return nil, nil, fmt.Errorf("madvise: %w", err)
    46  	}
    47  	mmapHandle2 := (*[MaxMapSize]byte)(unsafe.Pointer(&mmapHandle1[0]))
    48  	return mmapHandle1, mmapHandle2, nil
    49  }
    50  func Mmap(f *os.File, size int) ([]byte, *[MaxMapSize]byte, error) {
    51  	// Map the data file to memory.
    52  	mmapHandle1, err := unix.Mmap(int(f.Fd()), 0, size, syscall.PROT_READ, syscall.MAP_SHARED)
    53  	if err != nil {
    54  		return nil, nil, err
    55  	}
    56  
    57  	// Advise the kernel that the mmap is accessed randomly.
    58  	err = unix.Madvise(mmapHandle1, syscall.MADV_RANDOM)
    59  	if err != nil && !errors.Is(err, syscall.ENOSYS) {
    60  		// Ignore not implemented error in kernel because it still works.
    61  		return nil, nil, fmt.Errorf("madvise: %w", err)
    62  	}
    63  	mmapHandle2 := (*[MaxMapSize]byte)(unsafe.Pointer(&mmapHandle1[0]))
    64  	return mmapHandle1, mmapHandle2, nil
    65  }
    66  
    67  func MadviseSequential(mmapHandle1 []byte) error {
    68  	err := unix.Madvise(mmapHandle1, syscall.MADV_SEQUENTIAL)
    69  	if err != nil && !errors.Is(err, syscall.ENOSYS) {
    70  		// Ignore not implemented error in kernel because it still works.
    71  		return fmt.Errorf("madvise: %w", err)
    72  	}
    73  	return nil
    74  }
    75  
    76  func MadviseNormal(mmapHandle1 []byte) error {
    77  	err := unix.Madvise(mmapHandle1, syscall.MADV_NORMAL)
    78  	if err != nil && !errors.Is(err, syscall.ENOSYS) {
    79  		// Ignore not implemented error in kernel because it still works.
    80  		return fmt.Errorf("madvise: %w", err)
    81  	}
    82  	return nil
    83  }
    84  
    85  func MadviseWillNeed(mmapHandle1 []byte) error {
    86  	err := unix.Madvise(mmapHandle1, syscall.MADV_WILLNEED)
    87  	if err != nil && !errors.Is(err, syscall.ENOSYS) {
    88  		// Ignore not implemented error in kernel because it still works.
    89  		return fmt.Errorf("madvise: %w", err)
    90  	}
    91  	return nil
    92  }
    93  
    94  func MadviseRandom(mmapHandle1 []byte) error {
    95  	err := unix.Madvise(mmapHandle1, syscall.MADV_RANDOM)
    96  	if err != nil && !errors.Is(err, syscall.ENOSYS) {
    97  		// Ignore not implemented error in kernel because it still works.
    98  		return fmt.Errorf("madvise: %w", err)
    99  	}
   100  	return nil
   101  }
   102  
   103  // munmap unmaps a DB's data file from memory.
   104  func Munmap(mmapHandle1 []byte, _ *[MaxMapSize]byte) error {
   105  	// Ignore the unmap if we have no mapped data.
   106  	if mmapHandle1 == nil {
   107  		return nil
   108  	}
   109  	// Unmap using the original byte slice.
   110  	err := unix.Munmap(mmapHandle1)
   111  	return err
   112  }