Class: Rubcask::DataFile

Inherits:
Object
  • Object
show all
Extended by:
Forwardable
Defined in:
lib/rubcask/data_file.rb

Overview

DataFile is a file where the key and values are actually stored

Defined Under Namespace

Classes: AppendResult

Constant Summary collapse

HEADER_FORMAT =
"NQ>nN"
HEADER_WITHOUT_CRC_FORMAT =
"Q>nN"

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(file, file_size) ⇒ DataFile

Returns a new instance of DataFile.

Parameters:

  • file (File)

    File with the data

  • file_size (Integer)

    Current size of ‘file` in bytes



20
21
22
23
# File 'lib/rubcask/data_file.rb', line 20

def initialize(file, file_size)
  @file = file
  @write_pos = file_size
end

Instance Attribute Details

#write_posObject (readonly)

Returns the value of attribute write_pos.



13
14
15
# File 'lib/rubcask/data_file.rb', line 13

def write_pos
  @write_pos
end

Instance Method Details

#[](offset, size = nil) ⇒ Object

Fetch entry at given offset. Optional size parameter is size of the record. With it we make one less I/O

Parameters:

  • offset (Integer)

    File offset in bytes

  • size (Integer, nil) (defaults to: nil)

    Record size in bytes



29
30
31
32
# File 'lib/rubcask/data_file.rb', line 29

def [](offset, size = nil)
  seek(offset)
  read(size)
end

#append(entry) ⇒ AppendResult

Append a record at the end of the file

Parameters:

  • entry (DataEntry)

    Entry to write to the file

Returns:

  • (AppendResult)

    struct containing position and size of the record



71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
# File 'lib/rubcask/data_file.rb', line 71

def append(entry)
  current_pos = @write_pos

  key_size = entry.key.bytesize
  value_size = entry.value.bytesize

  crc = Zlib.crc32([
    entry.expire_timestamp,
    key_size,
    value_size
  ].pack(HEADER_WITHOUT_CRC_FORMAT) + entry.key + entry.value)
  @write_pos += @file.write(
    [crc, entry.expire_timestamp, key_size, value_size].pack(HEADER_FORMAT),
    entry.key,
    entry.value
  )
  @file.flush
  AppendResult.new(current_pos, @write_pos - current_pos)
end

#each {|| ... } ⇒ Enumerator

yields each record in the file

Yield Parameters:

Returns:

  • (Enumerator)

    if no block given



37
38
39
40
41
42
43
44
45
46
47
# File 'lib/rubcask/data_file.rb', line 37

def each
  return to_enum(__method__) unless block_given?

  seek(0)

  loop do
    val = read
    break unless val
    yield val
  end
end

#read(size = nil) ⇒ DataEntry?

Read entry at the current file position

Returns:

  • (DataEntry)
  • (nil)

    if at the end of file

Raises:



53
54
55
56
57
58
59
60
61
62
63
64
65
# File 'lib/rubcask/data_file.rb', line 53

def read(size = nil)
  io = size ? StringIO.new(@file.read(size)) : @file
  header = io.read(18)

  return nil unless header

  crc, expire_timestamp, key_size, value_size = header.unpack(HEADER_FORMAT)
  key = io.read(key_size)
  value = io.read(value_size)

  raise ChecksumError, "Checksums do not match" if crc != Zlib.crc32(header[4..] + key + value)
  DataEntry.new(expire_timestamp, key, value)
end