Class: Rubcask::HintedFile

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

Overview

HintedFile represents DataFile with the associated hint file it delegated all read/write responsibility to the @data_file

Constant Summary collapse

ID_REGEX =
/(\d+)\.data$/
HINT_EXTENSION_REGEX =
/\.data$/

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(file_path, os_sync: false, read_only: false, ruby_sync: false) ⇒ HintedFile

Returns a new instance of HintedFile.

Parameters:

  • file_path (String)

    Path of the data_file

  • os_sync (Boolean) (defaults to: false)

    Should O_SYNC flag be used on the data file?

  • read_only (Boolean) (defaults to: false)

    Should the data file be opened read-only?

  • ruby_sync (Boolean) (defaults to: false)

    Should ruby I/O buffers by bupassed?



31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# File 'lib/rubcask/hinted_file.rb', line 31

def initialize(file_path, os_sync: false, read_only: false, ruby_sync: false)
  @id = file_path.scan(ID_REGEX)[0][0].to_i
  @hint_path = file_path.sub(HINT_EXTENSION_REGEX, ".hint")
  @path = file_path
  @read_only = read_only

  io = nil
  size = nil
  flags = (os_sync && ruby_sync) ? File::SYNC : 0
  if File.exist?(file_path)
    size = File.size(file_path)
    @dirty = false
    io = File.open(file_path, "#{read_only ? "r" : "a+"}b", flags: flags)
  else # If file does not exist we ignore read_only as it does not make sense
    size = 0
    @dirty = true
    io = File.open(file_path, "a+b", flags: flags)
  end
  @data_file = DataFile.new(io, size)

  if ruby_sync
    @data_file.sync = true
  end
end

Instance Attribute Details

#hint_pathString (readonly)

Returns Path of the hint file associated with the data file.

Returns:

  • (String)

    Path of the hint file associated with the data file



25
26
27
# File 'lib/rubcask/hinted_file.rb', line 25

def hint_path
  @hint_path
end

#idInteger (readonly)

Returns id of the file.

Returns:

  • (Integer)

    id of the file



22
23
24
# File 'lib/rubcask/hinted_file.rb', line 22

def id
  @id
end

#pathString (readonly)

Returns path of the file.

Returns:

  • (String)

    path of the file



19
20
21
# File 'lib/rubcask/hinted_file.rb', line 19

def path
  @path
end

Instance Method Details

#append(entry) ⇒ KeydirEntry

Appends the entry to the end of the file

Parameters:

Returns:



71
72
73
74
75
76
77
78
# File 'lib/rubcask/hinted_file.rb', line 71

def append(entry)
  if !dirty?
    FileUtils.rm_f(hint_path)
    @dirty = true
  end
  write_entry = @data_file.append(entry)
  KeydirEntry.new(id, write_entry.value_size, write_entry.value_pos, entry.expire_timestamp)
end

#dirty?Boolean

Returns true if there were any appends to the data file.

Returns:

  • (Boolean)

    true if there were any appends to the data file



111
112
113
# File 'lib/rubcask/hinted_file.rb', line 111

def dirty?
  @dirty
end

#each_keydir_entry {|keydir_entry| ... } ⇒ Enumerator

yields every KeydirEntry in the file

Yields:

  • (keydir_entry)

Yield Parameters:

Returns:

  • (Enumerator)

    if no block given



60
61
62
63
64
65
66
# File 'lib/rubcask/hinted_file.rb', line 60

def each_keydir_entry(&block)
  return to_enum(__method__) unless block
  if has_hint_file?
    return each_hint_file_keydir_entry(&block)
  end
  each_data_file_keydir_entry(&block)
end

#has_hint_file?Boolean

Returns true if hint path exists.

Returns:

  • (Boolean)

    true if hint path exists



106
107
108
# File 'lib/rubcask/hinted_file.rb', line 106

def has_hint_file?
  File.exist?(hint_path)
end

#save_hint_fileObject

Creates a new hint file



81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
# File 'lib/rubcask/hinted_file.rb', line 81

def save_hint_file
  tempfile = Tempfile.new("hint")
  current_pos = 0
  map = {}
  data_file.each do |entry|
    new_pos = data_file.pos
    new_entry = HintEntry.new(entry.expire_timestamp, entry.key, current_pos, new_pos - current_pos)
    current_pos = new_pos
    map[entry.key] = new_entry
  end

  begin
    hint_file = HintFile.new(tempfile)
    map.each_value do |entry|
      hint_file.append(entry)
    end
    hint_file.close
    FileUtils.mv(tempfile.path, hint_path)
    @dirty = false
  ensure
    tempfile.close(true)
  end
end