github.com/scottcagno/storage@v1.8.0/pkg/_se/record.go (about)

     1  package _se
     2  
     3  import (
     4  	"encoding/binary"
     5  	"fmt"
     6  	"hash/crc32"
     7  	"io"
     8  	"unsafe"
     9  )
    10  
    11  const (
    12  	headerSize = int(unsafe.Sizeof(header{}))
    13  	magicIdent = 0xdeadbeef
    14  )
    15  
    16  type header struct {
    17  	id     uint32 // 4 bytes
    18  	crc    uint32 // 4 bytes
    19  	magic  uint32 // 4 bytes
    20  	pages  uint16 // 2 bytes
    21  	length uint16 // 2 bytes
    22  }
    23  
    24  func (h *header) String() string {
    25  	return fmt.Sprintf("header:\tid=%d, crc=%d, magic=%d, pages=%d, length=%d",
    26  		h.id, h.crc, h.magic, h.pages, h.length)
    27  }
    28  
    29  type record struct {
    30  	*header
    31  	data    []byte
    32  	padding int
    33  }
    34  
    35  func makeRecord(id uint32, data []byte) *record {
    36  	alignedSize := align(len(data)+headerSize, pageSize-1)
    37  	//fmt.Printf("alignedSize=%d, dataLen=%d, padding=%d\n", alignedSize, len(data), (alignedSize - (len(data) + headerSize)))
    38  	return &record{
    39  		header: &header{
    40  			id:     id,
    41  			crc:    crc32.ChecksumIEEE(data),
    42  			magic:  magicIdent,
    43  			pages:  uint16(alignedSize / pageSize),
    44  			length: uint16(len(data)),
    45  		},
    46  		data:    data,
    47  		padding: alignedSize - (len(data) + headerSize),
    48  	}
    49  }
    50  
    51  func (r *record) write(ws io.WriteSeeker) (int, error) {
    52  	var nn int
    53  	buf := make([]byte, r.header.pages*pageSize)
    54  	binary.LittleEndian.PutUint32(buf[nn:nn+4], r.header.id)
    55  	nn += 4
    56  	binary.LittleEndian.PutUint32(buf[nn:nn+4], r.header.crc)
    57  	nn += 4
    58  	binary.LittleEndian.PutUint32(buf[nn:nn+4], r.header.magic)
    59  	nn += 4
    60  	binary.LittleEndian.PutUint16(buf[nn:nn+2], r.header.pages)
    61  	nn += 2
    62  	binary.LittleEndian.PutUint16(buf[nn:nn+2], r.header.length)
    63  	nn += 2
    64  	copy(buf[nn:], r.data)
    65  	n, err := ws.Write(buf)
    66  	if err != nil {
    67  		return nn, err
    68  	}
    69  	nn += n
    70  	if r.padding > 0 {
    71  		_, err = ws.Write(make([]byte, r.padding))
    72  		if err != nil {
    73  			return nn, err
    74  		}
    75  	}
    76  	nn += r.padding
    77  	return nn, nil
    78  }
    79  
    80  func (r *record) read(rs io.ReadSeeker) (int, error) {
    81  	var nn int
    82  	var buf [headerSize]byte
    83  	n, err := rs.Read(buf[:])
    84  	if err != nil {
    85  		return n, err
    86  	}
    87  	h := new(header)
    88  	h.id = binary.LittleEndian.Uint32(buf[nn : nn+4])
    89  	nn += 4
    90  	h.crc = binary.LittleEndian.Uint32(buf[nn : nn+4])
    91  	nn += 4
    92  	h.magic = binary.LittleEndian.Uint32(buf[nn : nn+4])
    93  	nn += 4
    94  	h.pages = binary.LittleEndian.Uint16(buf[nn : nn+2])
    95  	nn += 2
    96  	h.length = binary.LittleEndian.Uint16(buf[nn : nn+2])
    97  	nn += 2
    98  	r.header = h
    99  	r.data = make([]byte, r.header.length)
   100  	n, err = rs.Read(r.data)
   101  	if err != nil {
   102  		return nn, err
   103  	}
   104  	nn += n
   105  	if r.padding > 0 {
   106  		_, err = rs.Seek(int64(r.padding), io.SeekCurrent)
   107  		if err != nil {
   108  			return nn, err
   109  		}
   110  	}
   111  	return nn, nil
   112  }
   113  
   114  func (r *record) raw() []byte {
   115  	var n int
   116  	buf := make([]byte, r.header.pages*pageSize)
   117  	binary.LittleEndian.PutUint32(buf[n:n+4], r.header.id)
   118  	n += 4
   119  	binary.LittleEndian.PutUint32(buf[n:n+4], r.header.crc)
   120  	n += 4
   121  	binary.LittleEndian.PutUint32(buf[n:n+4], r.header.magic)
   122  	n += 4
   123  	binary.LittleEndian.PutUint16(buf[n:n+2], r.header.pages)
   124  	n += 2
   125  	binary.LittleEndian.PutUint16(buf[n:n+2], r.header.length)
   126  	n += 2
   127  	n += copy(buf[n:], r.data)
   128  	return buf
   129  }
   130  
   131  func (r *record) String() string {
   132  	ss := fmt.Sprintf("%s\n", r.header)
   133  	ss += fmt.Sprintf("record:\tpadding=%d, data=%q", r.padding, r.data)
   134  	return ss
   135  }