xchan.rb 0.17.0 → 0.17.1

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: bf2db46e92eb29ed0182377c209a8ff7511460d22a73225616c719cd05372884
4
- data.tar.gz: 05b70d50483d354f79e29f9219628c44cb6f4b25e63cbd5aee7e0c0a14da8865
3
+ metadata.gz: 5509107cf1cda5e847f3c15e19c81ba9323c2dbb524a7ef808eeb820d5bcdeb9
4
+ data.tar.gz: 43deff543ee38ace3ca8a083a043eb1c6bbedec9143bd2c8e17de50f13127031
5
5
  SHA512:
6
- metadata.gz: f8fb7b0f73b09c4593dfa7892fd3e0061dce37242c0e9bebab0edd204cda399dd16c8fdbadce2ee6a5fac1fc6c1d583ad60eadd85c7ece4a145fdb18358aff0a
7
- data.tar.gz: ef454d2422ae0a719a19b7fad3bf670a3cc4b46154ea6e87786a4c6404bbe9f7af5437e81b3ed8651fa9e1f438ee7f43c38d10497ca9b50facd3aea3ededc7f0
6
+ metadata.gz: d5455dd6c714bc4060ec1f563b46d8a9eaee32e5aa58c2a2508de99f53fc29e346d07ac04e719822bc394b66ac6ba6ddf5585bf7958c606a0f1f375c113b4310
7
+ data.tar.gz: '09bd28506d18a63e8e917ad1189c708cc6643b852707508ee0edf563064bd3618d3ae251d85e06f618672c414537b4da3db0538b61e4c11c2a6c64fff3394f38'
@@ -12,7 +12,7 @@ jobs:
12
12
  fail-fast: false
13
13
  matrix:
14
14
  os: [ubuntu-latest, macos-latest]
15
- ruby: [3.1, 3.2]
15
+ ruby: [3.1, 3.2, 3.3]
16
16
  runs-on: ${{ matrix.os }}
17
17
  steps:
18
18
  - uses: actions/checkout@v2
@@ -23,4 +23,4 @@ jobs:
23
23
  - run: SERIALIZER=marshal bundle exec rake
24
24
  - run: SERIALIZER=json bundle exec rake
25
25
  - run: SERIALIZER=yaml bundle exec rake
26
- - run: SERIALIZER=plain bundle exec rake
26
+ - run: SERIALIZER=pure bundle exec rake
data/.gitlab-ci.yml CHANGED
@@ -9,4 +9,4 @@ test-ruby32:
9
9
  - SERIALIZER=marshal bundle exec rake
10
10
  - SERIALIZER=json bundle exec rake
11
11
  - SERIALIZER=yaml bundle exec rake
12
- - SERIALIZER=plain bundle exec rake
12
+ - SERIALIZER=pure bundle exec rake
data/lib/xchan/bytes.rb CHANGED
@@ -1,39 +1,31 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  ##
4
- # The {Chan::Bytes Chan::Bytes} class is similar
5
- # to an array, where each element represents the
6
- # number of bytes used to store an object on a
7
- # channel. When an object is written to a channel,
8
- # the array increases in size, and when an object
9
- # is read from a channel, the array decreases in
10
- # size.
4
+ # {Chan::Bytes Chan::Bytes} represents a collection
5
+ # of byte counts for each object stored on a channel.
6
+ # When an object is written to a channel, the collection
7
+ # increases in size, and when an object is read from
8
+ # a channel, the collection decreases in size.
11
9
  class Chan::Bytes
12
10
  require "json"
13
- require_relative "stat"
14
-
15
- ##
16
- # @return [Chan::Stat]
17
- attr_reader :stat
11
+ require_relative "counter"
18
12
 
19
13
  ##
20
14
  # @param [String] tmpdir
21
- # Path to a directory where temporary files will be stored.
15
+ # Directory where temporary files are stored
22
16
  #
23
17
  # @return [Chan::Bytes]
24
18
  def initialize(tmpdir)
25
- @serializer = JSON
26
19
  @io = Chan.temporary_file("xchan.bytes", tmpdir:)
27
20
  @io.sync = true
28
- @stat = Chan::Stat.new(tmpdir)
29
21
  write(@io, [])
30
22
  end
31
23
 
32
24
  ##
33
- # Insert a byte count at the head of the array
25
+ # Adds a count to the start of the collection
34
26
  #
35
27
  # @param [Integer] len
36
- # Number of bytes
28
+ # The bytesize of an object
37
29
  #
38
30
  # @return [void]
39
31
  def unshift(len)
@@ -41,15 +33,14 @@ class Chan::Bytes
41
33
  bytes = read(@io)
42
34
  bytes.unshift(len)
43
35
  write(@io, bytes)
44
- @stat.store(bytes_written: len)
45
36
  len
46
37
  end
47
38
 
48
39
  ##
49
- # Insert a byte count at the tail of the array
40
+ # Adds a count to the end of the collection
50
41
  #
51
42
  # @param [Integer] len
52
- # Number of bytes
43
+ # The bytesize of an object
53
44
  #
54
45
  # @return [void]
55
46
  def push(len)
@@ -57,25 +48,25 @@ class Chan::Bytes
57
48
  bytes = read(@io)
58
49
  bytes.push(len)
59
50
  write(@io, bytes)
60
- @stat.store(bytes_written: len)
61
51
  len
62
52
  end
63
53
 
64
54
  ##
55
+ # Removes a count from the start of the collection
56
+ #
65
57
  # @return [Integer]
66
- # Returns (and removes) a byte count from the head of the array
58
+ # Returns the removed byte count
67
59
  def shift
68
60
  bytes = read(@io)
69
61
  return 0 if bytes.size.zero?
70
62
  len = bytes.shift
71
63
  write(@io, bytes)
72
- @stat.store(bytes_read: len)
73
64
  len
74
65
  end
75
66
 
76
67
  ##
77
68
  # @return [Integer]
78
- # Returns the size of the array
69
+ # Returns the number of objects in the collection
79
70
  def size
80
71
  read(@io).size
81
72
  end
@@ -100,10 +91,10 @@ class Chan::Bytes
100
91
  end
101
92
 
102
93
  def serialize(bytes)
103
- @serializer.dump(bytes)
94
+ JSON.dump(bytes)
104
95
  end
105
96
 
106
97
  def deserialize(bytes)
107
- @serializer.load(bytes)
98
+ JSON.load(bytes)
108
99
  end
109
100
  end
@@ -1,33 +1,32 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  ##
4
- # The {Chan::Stat Chan::Stat} class provides statistics
5
- # (eg number of bytes read, number of bytes written) for
6
- # a given channel.
7
- class Chan::Stat
4
+ # {Chan::Counter Chan::Counter} provides a counter
5
+ # for the number of written and received bytes on a
6
+ # given channel.
7
+ class Chan::Counter
8
8
  require "json"
9
9
 
10
10
  ##
11
11
  # @param [String] tmpdir
12
- # Path to a directory where temporary files will be stored.
12
+ # Directory where temporary files are stored
13
13
  #
14
- # @return [Chan::Stat]
14
+ # @return [Chan::Counter]
15
15
  def initialize(tmpdir)
16
- @serializer = JSON
17
- @io = Chan.temporary_file("xchan.stat", tmpdir:)
16
+ @io = Chan.temporary_file("xchan.counter", tmpdir:)
18
17
  write(@io, {"bytes_read" => 0, "bytes_written" => 0})
19
18
  end
20
19
 
21
20
  ##
22
21
  # @return [Integer]
23
- # Returns the number of bytes written to a channel.
22
+ # Returns the number of bytes written to a channel
24
23
  def bytes_written
25
24
  read(@io).fetch("bytes_written")
26
25
  end
27
26
 
28
27
  ##
29
28
  # @return [Integer]
30
- # Returns the number of bytes read from a channel.
29
+ # Returns the number of bytes read from a channel
31
30
  def bytes_read
32
31
  read(@io).fetch("bytes_read")
33
32
  end
@@ -36,7 +35,7 @@ class Chan::Stat
36
35
  # @param [Hash] new_stat
37
36
  # @return [void]
38
37
  # @private
39
- def store(new_stat)
38
+ def increment!(new_stat)
40
39
  stat = read(@io)
41
40
  new_stat.each { stat[_1.to_s] += _2 }
42
41
  write(@io, stat)
@@ -54,10 +53,10 @@ class Chan::Stat
54
53
  end
55
54
 
56
55
  def serialize(bytes)
57
- @serializer.dump(bytes)
56
+ JSON.dump(bytes)
58
57
  end
59
58
 
60
59
  def deserialize(bytes)
61
- @serializer.load(bytes)
60
+ JSON.load(bytes)
62
61
  end
63
62
  end
@@ -39,25 +39,26 @@ class Chan::UNIXSocket
39
39
  @serializer = Chan.serializers[serializer]&.call || serializer
40
40
  @r, @w = ::UNIXSocket.pair(sock_type)
41
41
  @bytes = Chan::Bytes.new(tmpdir)
42
+ @counter = Chan::Counter.new(tmpdir)
42
43
  @lock = LockFile.new Chan.temporary_file("xchan.lock", tmpdir:)
43
44
  end
44
45
 
45
46
  ##
46
47
  # @return [<#dump, #load>]
47
- # Returns the serializer used by the channel.
48
+ # Returns the serializer used by the channel
48
49
  def serializer
49
50
  @serializer
50
51
  end
51
52
 
52
53
  ##
53
54
  # @return [Boolean]
54
- # Returns true when the channel is closed.
55
+ # Returns true when the channel is closed
55
56
  def closed?
56
57
  @r.closed? and @w.closed?
57
58
  end
58
59
 
59
60
  ##
60
- # Closes the channel.
61
+ # Closes the channel
61
62
  #
62
63
  # @raise [IOError]
63
64
  # When the channel is closed.
@@ -79,13 +80,13 @@ class Chan::UNIXSocket
79
80
  # Performs a blocking write
80
81
  #
81
82
  # @param [Object] object
82
- # An object to write to the channel.
83
+ # An object
83
84
  #
84
85
  # @raise [IOError]
85
- # When the channel is closed.
86
+ # When the channel is closed
86
87
  #
87
88
  # @return [Object]
88
- # Returns the number of bytes written to the channel.
89
+ # Returns the number of bytes written to the channel
89
90
  def send(object)
90
91
  send_nonblock(object)
91
92
  rescue Chan::WaitWritable, Chan::WaitLockable
@@ -97,24 +98,25 @@ class Chan::UNIXSocket
97
98
  # Performs a non-blocking write
98
99
  #
99
100
  # @param [Object] object
100
- # An object to write to the channel.
101
+ # An object
101
102
  #
102
103
  # @raise [IOError]
103
- # When the channel is closed.
104
+ # When the channel is closed
104
105
  #
105
106
  # @raise [Chan::WaitWritable]
106
- # When a write to the underlying IO blocks.
107
+ # When a write to {#w} blocks
107
108
  #
108
109
  # @raise [Chan::WaitLockable]
109
- # When a write blocks because of a lock held by another process.
110
+ # When a write blocks because of a lock held by another process
110
111
  #
111
112
  # @return [Integer, nil]
112
- # Returns the number of bytes written to the channel.
113
+ # Returns the number of bytes written to the channel
113
114
  def send_nonblock(object)
114
115
  @lock.lock_nonblock
115
116
  raise IOError, "channel closed" if closed?
116
117
  len = @w.write_nonblock(serialize(object))
117
118
  @bytes.push(len)
119
+ @counter.increment!(bytes_written: len)
118
120
  len.tap { @lock.release }
119
121
  rescue IOError, IO::WaitWritable, Errno::ENOBUFS => ex
120
122
  @lock.release
@@ -134,10 +136,10 @@ class Chan::UNIXSocket
134
136
  # Performs a blocking read
135
137
  #
136
138
  # @raise [IOError]
137
- # When the channel is closed.
139
+ # When the channel is closed
138
140
  #
139
141
  # @return [Object]
140
- # Returns an object from the channel.
142
+ # Returns an object from the channel
141
143
  def recv
142
144
  recv_nonblock
143
145
  rescue Chan::WaitReadable
@@ -152,21 +154,22 @@ class Chan::UNIXSocket
152
154
  # Performs a non-blocking read
153
155
  #
154
156
  # @raise [IOError]
155
- # When the channel is closed.
157
+ # When the channel is closed
156
158
  #
157
159
  # @raise [Chan::WaitReadable]
158
- # When a read from the underlying IO blocks.
160
+ # When a read from {#r} blocks
159
161
  #
160
162
  # @raise [Chan::WaitLockable]
161
- # When a read blocks because of a lock held by another process.
163
+ # When a read blocks because of a lock held by another process
162
164
  #
163
165
  # @return [Object]
164
- # Returns an object from the channel.
166
+ # Returns an object from the channel
165
167
  def recv_nonblock
166
168
  @lock.lock_nonblock
167
169
  raise IOError, "closed channel" if closed?
168
170
  len = @bytes.shift
169
171
  obj = deserialize(@r.read_nonblock(len.zero? ? 1 : len))
172
+ @counter.increment!(bytes_read: len)
170
173
  obj.tap { @lock.release }
171
174
  rescue IOError => ex
172
175
  @lock.release
@@ -190,7 +193,7 @@ class Chan::UNIXSocket
190
193
  # ch.to_a.last # => 4
191
194
  #
192
195
  # @return [Array<Object>]
193
- # Returns the consumed contents of the channel.
196
+ # Returns the contents of the channel
194
197
  def to_a
195
198
  lock do
196
199
  [].tap { _1.push(recv) until empty? }
@@ -199,7 +202,7 @@ class Chan::UNIXSocket
199
202
 
200
203
  ##
201
204
  # @return [Boolean]
202
- # Returns true when the channel is empty.
205
+ # Returns true when the channel is empty
203
206
  def empty?
204
207
  return true if closed?
205
208
  lock { size.zero? }
@@ -210,17 +213,17 @@ class Chan::UNIXSocket
210
213
 
211
214
  ##
212
215
  # @return [Integer]
213
- # Returns the total number of bytes written to the channel.
216
+ # Returns the total number of bytes written to the channel
214
217
  def bytes_sent
215
- lock { @bytes.stat.bytes_written }
218
+ lock { @counter.bytes_written }
216
219
  end
217
220
  alias_method :bytes_written, :bytes_sent
218
221
 
219
222
  ##
220
223
  # @return [Integer]
221
- # Returns the total number of bytes read from the channel.
224
+ # Returns the total number of bytes read from the channel
222
225
  def bytes_received
223
- lock { @bytes.stat.bytes_read }
226
+ lock { @counter.bytes_read }
224
227
  end
225
228
  alias_method :bytes_read, :bytes_received
226
229
 
data/lib/xchan/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Chan
4
- VERSION = "0.17.0"
4
+ VERSION = "0.17.1"
5
5
  end
data/test/xchan_test.rb CHANGED
@@ -4,7 +4,7 @@ require_relative "setup"
4
4
 
5
5
  class Chan::Test < Test::Unit::TestCase
6
6
  def setup
7
- @ch = xchan ENV.fetch("SERIALIZER", "marshal").to_sym
7
+ @ch = xchan(serializer)
8
8
  end
9
9
 
10
10
  def teardown
@@ -17,9 +17,13 @@ class Chan::Test < Test::Unit::TestCase
17
17
  @ch
18
18
  end
19
19
 
20
+ def serializer
21
+ ENV.fetch("SERIALIZER", "pure").to_sym
22
+ end
23
+
20
24
  def object
21
- case ENV["SERIALIZER"]
22
- when "plain" then "xchan"
25
+ case serializer
26
+ when :pure then "xchan"
23
27
  else %w[xchan]
24
28
  end
25
29
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: xchan.rb
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.17.0
4
+ version: 0.17.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - '0x1eef'
@@ -127,7 +127,7 @@ files:
127
127
  - Rakefile.rb
128
128
  - lib/xchan.rb
129
129
  - lib/xchan/bytes.rb
130
- - lib/xchan/stat.rb
130
+ - lib/xchan/counter.rb
131
131
  - lib/xchan/tempfile.rb
132
132
  - lib/xchan/unix_socket.rb
133
133
  - lib/xchan/version.rb