rubcask 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c7d54e3884c99955ecbab6624997f84c8469d1f60ad73a34631e206efffebbeb
4
- data.tar.gz: d2c62d450a8ebd9abfc5e12ac26c2747365afbe98ff72fe8117fc8659c02b1d0
3
+ metadata.gz: '0568bcb47da50a78d9679c88b735cb5b2c259efb00297bb87f749463520cb371'
4
+ data.tar.gz: 210aaa3e1dd5eb5b0dd26a105f3151717661ff92f24ff54ded3077306b07b838
5
5
  SHA512:
6
- metadata.gz: 6be6603b4238edd7a93548e6440c4dcee3263afb254b40999b774e7b8e60dc39d021457bd88a4f3cc0017a2812685c48d574aacbc1f35a0ae0eda35c46fad468
7
- data.tar.gz: 57e451dd32e7e555e6692bbaf441370a90df623cffef4aa52169db0869ad1b99650372e20abed61ca0eefe3f1247ca4e8ae39f06d3a142d2b932713387c787dc
6
+ metadata.gz: f52adc24589f583eb1e777c5fe42c1c672e9b2c39e6cd2da5ca75f9be61d7c208a90d146a43adee28978c6217e3557e3b2c89a4290051f10fc2bf92290ab3d6c
7
+ data.tar.gz: 626f339669b988a5f844b90285e92985122a08d6144d22bd1a311411ca298876656ef375b13e4230da1c49edb00120191d53d046358fef107e13b34ab1634812
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- rubcask (0.1.0)
4
+ rubcask (0.2.0)
5
5
  concurrent-ruby (~> 1.1)
6
6
 
7
7
  GEM
@@ -9,7 +9,7 @@ GEM
9
9
  specs:
10
10
  ast (2.4.2)
11
11
  benchmark-ips (2.10.0)
12
- concurrent-ruby (1.1.10)
12
+ concurrent-ruby (1.2.0)
13
13
  docile (1.4.0)
14
14
  json (2.6.3)
15
15
  json (2.6.3-java)
@@ -22,18 +22,35 @@ module Rubcask
22
22
  @write_pos = file_size
23
23
  end
24
24
 
25
+ # @!macro [new] might_change_pos
26
+ # @note Calling this method might change `pos` of the `file`
27
+
28
+ # @!macro [new] no_change_pos
29
+ # @note Calling this method will not change `pos` of the `file`
30
+
31
+ # @!macro [new] read_result_return
32
+ # @return [DataEntry]
33
+ # @return [nil] if at the end of file
34
+ # @raise [ChecksumError] if the entry has an incorrect checksum
35
+
25
36
  # Fetch entry at given offset.
26
- # Optional size parameter is size of the record. With it we make one less I/O
37
+ # With optional size parameter we can do less I/O operations.
38
+ # @macro might_change_pos
27
39
  # @param [Integer] offset File offset in bytes
28
- # @param [Integer, nil] size Record size in bytes
40
+ # @param [Integer, nil] size Entry size in bytes
41
+ # @macro read_result_return
29
42
  def [](offset, size = nil)
30
- seek(offset)
31
- read(size)
43
+ if size.nil?
44
+ seek(offset)
45
+ return read
46
+ end
47
+ pread(offset, size)
32
48
  end
33
49
 
34
- # yields each record in the file
50
+ # yields each entry in the file
51
+ # @macro might_change_pos
35
52
  # @return [Enumerator] if no block given
36
- # @yieldparam [DataEntry]
53
+ # @yieldparam [DataEntry] data_entry Entry from the file
37
54
  def each
38
55
  return to_enum(__method__) unless block_given?
39
56
 
@@ -46,28 +63,30 @@ module Rubcask
46
63
  end
47
64
  end
48
65
 
49
- # Read entry at the current file position
50
- # @return [DataEntry]
51
- # @return [nil] if at the end of file
52
- # @raise [ChecksumError] if the entry has an incorrect checksum
66
+ # Read an entry at the current file position
67
+ # @macro might_change_pos
68
+ # @param [Integer, nil] size Entry size in bytes
69
+ # @macro read_result_return
53
70
  def read(size = nil)
54
- io = size ? StringIO.new(@file.read(size)) : @file
55
- header = io.read(18)
56
-
57
- return nil unless header
58
-
59
- crc, expire_timestamp, key_size, value_size = header.unpack(HEADER_FORMAT)
60
- key = io.read(key_size)
61
- value = io.read(value_size)
71
+ read_from_io(
72
+ size ? StringIO.new(@file.read(size)) : @file
73
+ )
74
+ end
62
75
 
63
- raise ChecksumError, "Checksums do not match" if crc != Zlib.crc32(header[4..] + key + value)
64
- DataEntry.new(expire_timestamp, key, value)
76
+ # Fetch an entry at given offset and with provided size
77
+ # @macro no_change_pos
78
+ # @param [Integer] offset File offset in bytes
79
+ # @param [Integer] size Entry size in bytes
80
+ # @macro read_result_return
81
+ def pread(offset, size)
82
+ read_from_io(StringIO.new(@file.pread(size, offset)))
65
83
  end
66
84
 
67
85
  AppendResult = Struct.new(:value_pos, :value_size)
68
- # Append a record at the end of the file
86
+ # Append an entry at the end of the file
87
+ # @macro no_change_pos
69
88
  # @param [DataEntry] entry Entry to write to the file
70
- # @return [AppendResult] struct containing position and size of the record
89
+ # @return [AppendResult] struct containing position and size of the entry
71
90
  def append(entry)
72
91
  current_pos = @write_pos
73
92
 
@@ -87,5 +106,20 @@ module Rubcask
87
106
  @file.flush
88
107
  AppendResult.new(current_pos, @write_pos - current_pos)
89
108
  end
109
+
110
+ private
111
+
112
+ def read_from_io(io)
113
+ header = io.read(18)
114
+
115
+ return nil unless header
116
+
117
+ crc, expire_timestamp, key_size, value_size = header.unpack(HEADER_FORMAT)
118
+ key = io.read(key_size)
119
+ value = io.read(value_size)
120
+
121
+ raise ChecksumError, "Checksums do not match" if crc != Zlib.crc32(header[4..] + key + value)
122
+ DataEntry.new(expire_timestamp, key, value)
123
+ end
90
124
  end
91
125
  end
@@ -1,7 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "concurrent"
3
+ require "concurrent/atomic/atomic_fixnum"
4
+ require "concurrent/atomic/reentrant_read_write_lock"
4
5
 
6
+ require "fiber" # rubocop:disable Lint/RedundantRequireStatement It is needed for `Fiber.current`(used by concurrent) in some rubies
5
7
  require "forwardable"
6
8
  require "logger"
7
9
  require "monitor"
@@ -131,11 +133,11 @@ module Rubcask
131
133
  end
132
134
 
133
135
  data_file = @files[entry.file_id]
134
- data_file.synchronize do
135
- value = data_file[entry.value_pos, entry.value_size].value
136
- return nil if Tombstone.is_tombstone?(value)
137
- return value
138
- end
136
+
137
+ # We are using pread so there's no need to synchronize the read
138
+ value = data_file.pread(entry.value_pos, entry.value_size).value
139
+ return nil if Tombstone.is_tombstone?(value)
140
+ return value
139
141
  end
140
142
  end
141
143
 
@@ -190,21 +192,16 @@ module Rubcask
190
192
  # @yieldparam [String] value
191
193
  # @macro lock_block_for_iteration
192
194
  # @macro key_any_order
193
- # @return Enumerator if block not given
195
+ # @return [Enumerator<Array(String, String)>] if no block given
194
196
  def each
195
197
  return to_enum(__method__) unless block_given?
196
198
 
197
199
  @lock.with_read_lock do
198
200
  @keydir.each do |key, entry|
199
201
  file = @files[entry.file_id]
200
- file.mon_enter
201
- begin
202
- value = file[entry.value_pos, entry.value_size].value
203
- next if Tombstone.is_tombstone?(value)
204
- yield [key, value]
205
- ensure
206
- file.mon_exit
207
- end
202
+ value = file[entry.value_pos, entry.value_size].value
203
+ next if Tombstone.is_tombstone?(value)
204
+ yield [key, value]
208
205
  end
209
206
  end
210
207
  end
@@ -213,7 +210,7 @@ module Rubcask
213
210
  # @macro deleted_keys
214
211
  # @macro key_any_order
215
212
  # @macro lock_block_for_iteration
216
- # @return Enumerator if block not given
213
+ # @return [Enumerator<String>] if no block given
217
214
  def each_key(&block)
218
215
  return to_enum(__method__) unless block
219
216
 
@@ -13,7 +13,7 @@ module Rubcask
13
13
  ID_REGEX = /(\d+)\.data$/
14
14
  HINT_EXTENSION_REGEX = /\.data$/
15
15
 
16
- def_delegators :@data_file, :seek, :[], :close, :flush, :each, :pos, :write_pos
16
+ def_delegators :@data_file, :seek, :[], :pread, :close, :flush, :each, :pos, :write_pos
17
17
 
18
18
  # @return [String] path of the file
19
19
  attr_reader :path
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "stringio"
4
+
3
5
  require_relative "../bytes"
4
6
  require_relative "../protocol"
5
7
  require_relative "config"
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "concurrent"
3
+ require "concurrent/timer_task"
4
+
4
5
  require_relative "./config"
5
6
  require_relative "./runner/config"
6
7
  require_relative "../config"
@@ -3,7 +3,6 @@
3
3
  require "logger"
4
4
  require "socket"
5
5
  require "io/wait"
6
- require "stringio"
7
6
 
8
7
  require_relative "../bytes"
9
8
  require_relative "../protocol"
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Rubcask
4
- VERSION = "0.1.0"
4
+ VERSION = "0.2.0"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubcask
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Marcin Henryk Bartkowiak
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-01-28 00:00:00.000000000 Z
11
+ date: 2023-02-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: concurrent-ruby