rubcask 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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