daybreak 0.1.2 → 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
data/lib/daybreak.rb CHANGED
@@ -4,8 +4,6 @@ require 'fcntl'
4
4
  require 'zlib'
5
5
 
6
6
  require 'daybreak/version'
7
- require 'daybreak/locking'
8
7
  require 'daybreak/record'
9
8
  require 'daybreak/writer'
10
- require 'daybreak/reader'
11
9
  require 'daybreak/db'
data/lib/daybreak/db.rb CHANGED
@@ -16,7 +16,6 @@ module Daybreak
16
16
  def initialize(file, default=nil, &blk)
17
17
  @table = {}
18
18
  @file_name = file
19
- @reader = Reader.new(@file_name)
20
19
  @writer = Writer.new(@file_name)
21
20
  @default = block_given? ? blk : default
22
21
  read!
@@ -162,7 +161,13 @@ module Daybreak
162
161
  # Read all values from the log file. If you want to check for changed data
163
162
  # call this again.
164
163
  def read!
165
- @reader.read do |(key, data, deleted)|
164
+ buf = nil
165
+ File.open(@file_name, 'rb') do |fd|
166
+ fd.flock(File::LOCK_SH)
167
+ buf = fd.read
168
+ end
169
+ until buf.empty?
170
+ key, data, deleted = Record.deserialize(buf)
166
171
  if deleted
167
172
  @table.delete key
168
173
  else
@@ -9,7 +9,6 @@ module Daybreak
9
9
  class CorruptDataError < Exception; end
10
10
 
11
11
  extend self
12
- extend Locking
13
12
 
14
13
  # The mask a record uses to check for deletion.
15
14
  DELETION_MASK = 1 << 31
@@ -28,20 +27,17 @@ module Daybreak
28
27
 
29
28
  # Create a new record to read from IO.
30
29
  # @param [#read] io an IO instance to read from
31
- def read(io)
32
- lock io do
33
- record = []
34
- masked = read32(io)
35
- # Read the record's key bytes
36
- record << io.read(masked & (DELETION_MASK - 1)) <<
37
- # Read the record's value bytes
38
- io.read(read32(io)) <<
39
- # Set the deletion flag
40
- ((masked & DELETION_MASK) != 0)
41
- crc = io.read(4)
42
- raise CorruptDataError, 'CRC mismatch' unless crc == crc_string(key_data_string(record))
43
- record
44
- end
30
+ def deserialize(buf)
31
+ record = []
32
+ masked = read32(buf)
33
+ # Read the record's key bytes
34
+ record << buf.slice!(0, masked & (DELETION_MASK - 1)) <<
35
+ # Read the record's value bytes
36
+ buf.slice!(0, read32(buf)) <<
37
+ # Set the deletion flag
38
+ ((masked & DELETION_MASK) != 0)
39
+ raise CorruptDataError, 'CRC mismatch' unless buf.slice!(0, 4) == crc_string(key_data_string(record))
40
+ record
45
41
  end
46
42
 
47
43
  private
@@ -59,9 +55,8 @@ module Daybreak
59
55
  [length].pack('N') << data
60
56
  end
61
57
 
62
- def read32(io)
63
- raw = io.read(4)
64
- raw.unpack('N')[0]
58
+ def read32(buf)
59
+ buf.slice!(0, 4).unpack('N')[0]
65
60
  end
66
61
  end
67
62
  end
@@ -1,4 +1,4 @@
1
1
  module Daybreak
2
2
  # Updated using SemVer
3
- VERSION = "0.1.2"
3
+ VERSION = "0.1.3"
4
4
  end
@@ -40,8 +40,7 @@ module Daybreak
40
40
  private
41
41
 
42
42
  def open!
43
- @fd = File.open @file, 'a'
44
- @fd.binmode
43
+ @fd = File.open @file, 'ab'
45
44
 
46
45
  if defined?(Fcntl::O_NONBLOCK)
47
46
  f = @fd.fcntl(Fcntl::F_GETFL, 0)
@@ -52,8 +51,6 @@ module Daybreak
52
51
  # Workers handle the actual fiddly bits of asynchronous io and
53
52
  # and handle background writes.
54
53
  class Worker
55
- include Locking
56
-
57
54
  def initialize(fd)
58
55
  @queue = Queue.new
59
56
  @fd = fd
@@ -69,41 +66,50 @@ module Daybreak
69
66
  # Loop and block if we don't have work to do or if
70
67
  # the file isn't ready for another write just yet.
71
68
  def work
72
- buf = ''
73
- loop do
69
+ buf, finished = '', false
70
+ until finished && buf.empty?
74
71
  record = @queue.pop
75
- unless record
76
- @fd.flush
77
- break
72
+ if record
73
+ buf << Record.serialize(record)
74
+ else
75
+ finished = true
78
76
  end
79
- buf << Record.serialize(record)
80
77
  read, write = IO.select [], [@fd]
81
78
  if write and fd = write.first
82
- lock(fd, File::LOCK_EX) { buf = try_write fd, buf }
79
+ lock(fd) { buf = try_write fd, buf }
83
80
  end
84
81
  end
82
+ @fd.flush
85
83
  end
86
84
 
87
85
  # Try and write the buffer to the file via non blocking file writes.
88
86
  # If the write fails try again.
89
87
  def try_write(fd, buf)
90
- begin
91
- if defined?(Fcntl::O_NONBLOCK)
92
- s = fd.write_nonblock(buf)
93
- else
94
- s = fd.write(buf)
95
- end
96
- if s < buf.length
97
- buf = buf[s..-1] # didn't finish
98
- else
99
- buf = ''
100
- end
101
- rescue Errno::EAGAIN
102
- buf = buf # try this again
88
+ if defined?(Fcntl::O_NONBLOCK)
89
+ s = fd.write_nonblock(buf)
90
+ else
91
+ s = fd.write(buf)
103
92
  end
93
+ if s < buf.length
94
+ buf = buf[s..-1] # didn't finish
95
+ else
96
+ buf = ""
97
+ end
98
+ buf
99
+ rescue Errno::EAGAIN
104
100
  buf
105
101
  end
106
102
 
103
+ # Lock a file with the type <tt>lock</tt>
104
+ def lock(fd)
105
+ fd.flock File::LOCK_EX
106
+ begin
107
+ yield
108
+ ensure
109
+ fd.flock File::LOCK_UN
110
+ end
111
+ end
112
+
107
113
  # finish! and start up another worker thread.
108
114
  def flush!
109
115
  finish!
metadata CHANGED
@@ -1,61 +1,55 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: daybreak
3
- version: !ruby/object:Gem::Version
4
- hash: 31
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.3
5
5
  prerelease:
6
- segments:
7
- - 0
8
- - 1
9
- - 2
10
- version: 0.1.2
11
6
  platform: ruby
12
- authors:
7
+ authors:
13
8
  - Jeff Larson
14
9
  autorequire:
15
10
  bindir: bin
16
11
  cert_chain: []
17
-
18
- date: 2013-01-07 00:00:00 -05:00
19
- default_executable:
20
- dependencies:
21
- - !ruby/object:Gem::Dependency
12
+ date: 2013-01-08 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
22
15
  name: rake
23
- prerelease: false
24
- requirement: &id001 !ruby/object:Gem::Requirement
16
+ requirement: !ruby/object:Gem::Requirement
25
17
  none: false
26
- requirements:
27
- - - ">="
28
- - !ruby/object:Gem::Version
29
- hash: 3
30
- segments:
31
- - 0
32
- version: "0"
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
33
22
  type: :development
34
- version_requirements: *id001
35
- - !ruby/object:Gem::Dependency
36
- name: minitest
37
23
  prerelease: false
38
- requirement: &id002 !ruby/object:Gem::Requirement
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: minitest
32
+ requirement: !ruby/object:Gem::Requirement
39
33
  none: false
40
- requirements:
41
- - - ">="
42
- - !ruby/object:Gem::Version
43
- hash: 3
44
- segments:
45
- - 0
46
- version: "0"
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
47
38
  type: :development
48
- version_requirements: *id002
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
49
46
  description: A simple dimple key-value store for ruby.
50
- email:
47
+ email:
51
48
  - thejefflarson@gmail.com
52
49
  executables: []
53
-
54
50
  extensions: []
55
-
56
51
  extra_rdoc_files: []
57
-
58
- files:
52
+ files:
59
53
  - .gitignore
60
54
  - .travis.yml
61
55
  - .yardopts
@@ -67,8 +61,6 @@ files:
67
61
  - daybreak.gemspec
68
62
  - lib/daybreak.rb
69
63
  - lib/daybreak/db.rb
70
- - lib/daybreak/locking.rb
71
- - lib/daybreak/reader.rb
72
64
  - lib/daybreak/record.rb
73
65
  - lib/daybreak/version.rb
74
66
  - lib/daybreak/writer.rb
@@ -77,43 +69,36 @@ files:
77
69
  - test/prof.rb
78
70
  - test/test.rb
79
71
  - test/test_helper.rb
80
- has_rdoc: true
81
72
  homepage: http://propublica.github.com/daybreak/
82
- licenses:
73
+ licenses:
83
74
  - MIT
84
75
  post_install_message:
85
76
  rdoc_options: []
86
-
87
- require_paths:
77
+ require_paths:
88
78
  - lib
89
- required_ruby_version: !ruby/object:Gem::Requirement
79
+ required_ruby_version: !ruby/object:Gem::Requirement
90
80
  none: false
91
- requirements:
92
- - - ">="
93
- - !ruby/object:Gem::Version
94
- hash: 3
95
- segments:
96
- - 0
97
- version: "0"
98
- required_rubygems_version: !ruby/object:Gem::Requirement
81
+ requirements:
82
+ - - ! '>='
83
+ - !ruby/object:Gem::Version
84
+ version: '0'
85
+ required_rubygems_version: !ruby/object:Gem::Requirement
99
86
  none: false
100
- requirements:
101
- - - ">="
102
- - !ruby/object:Gem::Version
103
- hash: 3
104
- segments:
105
- - 0
106
- version: "0"
87
+ requirements:
88
+ - - ! '>='
89
+ - !ruby/object:Gem::Version
90
+ version: '0'
107
91
  requirements: []
108
-
109
92
  rubyforge_project:
110
- rubygems_version: 1.6.2
93
+ rubygems_version: 1.8.24
111
94
  signing_key:
112
95
  specification_version: 3
113
- summary: Daybreak provides an in memory key-value store that is easily enumerable in ruby.
114
- test_files:
96
+ summary: Daybreak provides an in memory key-value store that is easily enumerable
97
+ in ruby.
98
+ test_files:
115
99
  - test/bench.rb
116
100
  - test/compare.rb
117
101
  - test/prof.rb
118
102
  - test/test.rb
119
103
  - test/test_helper.rb
104
+ has_rdoc:
@@ -1,14 +0,0 @@
1
- module Daybreak
2
- # File locking mixin
3
- module Locking
4
- # Lock a file with the type <tt>lock</tt>
5
- def lock(fd, lock=File::LOCK_SH)
6
- fd.flock lock
7
- begin
8
- yield
9
- ensure
10
- fd.flock File::LOCK_UN
11
- end
12
- end
13
- end
14
- end
@@ -1,26 +0,0 @@
1
- module Daybreak
2
- # Class for building out the table, you shouldn't need to access this
3
- # class directly. Readers are responsible for reading each record in
4
- # the file and yeilding the parsed records.
5
- class Reader
6
- # @param [String] file the file to read from
7
- def initialize(file)
8
- @file_name = file
9
- end
10
-
11
- # Read all values from the aof file.
12
- #
13
- # Right now this is really expensive, every call to read will
14
- # close and reread the whole db file, but since cross process
15
- # consistency is handled by the user, this should be fair warning.
16
- def read
17
- File.open(@file_name, 'r') do |fd|
18
- fd.binmode
19
- fd.advise(:sequential) if fd.respond_to? :advise
20
- while !fd.eof?
21
- yield Record.read(fd)
22
- end
23
- end
24
- end
25
- end
26
- end