drip 0.1.0 → 0.1.1
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 +5 -5
- data/drip.gemspec +3 -1
- data/lib/drip/version.rb +1 -1
- data/lib/drip3.rb +410 -0
- data/test/basic3.rb +250 -0
- metadata +34 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: ccc378c36cdf4c16d9f69116b4921264a81c861ed30fd27453ed6c52f257b03c
|
4
|
+
data.tar.gz: 1f9f813e80c22eb8788289b79e59ed53e96e70fe32d6c572cc905274a3906441
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: '038ac25011da60f555b56a65b69060befe154f938263a0cb3cbd541324cee6841d2a7cf482b1b1b3027152fd395fa9947d5a995a0b506a1ecd279de1dc75f5e8'
|
7
|
+
data.tar.gz: 0b93f499b391e0a5d376f851746ba2c44dac5d5a2dba18016050cddf769a0c9ff75f9efc818c24267c1131751d1dd583e80c9eec69afdcb4dc3a16f1c393993b
|
data/drip.gemspec
CHANGED
@@ -12,7 +12,9 @@ Gem::Specification.new do |s|
|
|
12
12
|
s.description = ""
|
13
13
|
|
14
14
|
s.rubyforge_project = "drip"
|
15
|
-
s.add_dependency "rbtree"
|
15
|
+
s.add_dependency "rbtree"
|
16
|
+
s.add_development_dependency "test-unit"
|
17
|
+
s.add_development_dependency "sqlite3"
|
16
18
|
s.files = `git ls-files`.split("\n")
|
17
19
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
20
|
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
data/lib/drip/version.rb
CHANGED
data/lib/drip3.rb
ADDED
@@ -0,0 +1,410 @@
|
|
1
|
+
require 'drb/drb'
|
2
|
+
require 'rinda/tuplespace'
|
3
|
+
require 'enumerator'
|
4
|
+
require 'sqlite3'
|
5
|
+
|
6
|
+
class SQLite3::Database
|
7
|
+
def statement(s)
|
8
|
+
if @cache.nil?
|
9
|
+
@cache = Hash.new { |h, k| h[k] = self.prepare(k) }
|
10
|
+
end
|
11
|
+
@cache[s]
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class SQLite3::Statement
|
16
|
+
def get_first_row(*bind_vars)
|
17
|
+
execute(*bind_vars).first
|
18
|
+
end
|
19
|
+
|
20
|
+
def get_first_value(*bind_vars)
|
21
|
+
execute(*bind_vars).each { |row| return row[0] }
|
22
|
+
nil
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
class Drip3
|
27
|
+
include DRbUndumped
|
28
|
+
INF = 1.0/0.0
|
29
|
+
|
30
|
+
def inspect; to_s; end
|
31
|
+
|
32
|
+
def initialize(dir)
|
33
|
+
@event = Rinda::TupleSpace.new(5)
|
34
|
+
@event.write([:last, 1])
|
35
|
+
setup_db(dir)
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.time_to_key(time)
|
39
|
+
time.tv_sec * 1000000 + time.tv_usec
|
40
|
+
end
|
41
|
+
|
42
|
+
def time_to_key(time)
|
43
|
+
self.class.time_to_key(time)
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.key_to_time(key)
|
47
|
+
Time.at(*key.divmod(1000000))
|
48
|
+
end
|
49
|
+
|
50
|
+
def key_to_time(key)
|
51
|
+
self.class.key_to_time(key)
|
52
|
+
end
|
53
|
+
|
54
|
+
def write(obj, tag=nil)
|
55
|
+
write_after(Time.now, obj, tag)
|
56
|
+
end
|
57
|
+
|
58
|
+
def write_after(at, obj, tag=nil)
|
59
|
+
make_key(at) do |key|
|
60
|
+
do_write(key, obj, tag)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def write_at(at, obj, tag=nil)
|
65
|
+
make_key_at(at) do |key|
|
66
|
+
do_write(key, obj, tag)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def write_if_latest(cond, obj, tag=nil)
|
71
|
+
make_key(Time.now) do |key|
|
72
|
+
do_write(key, obj, tag, cond)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def fetch(key)
|
77
|
+
do_fetch(key)
|
78
|
+
end
|
79
|
+
alias [] fetch
|
80
|
+
|
81
|
+
def head(n=1, tag=nil)
|
82
|
+
if tag
|
83
|
+
do_head_tag(n, tag)
|
84
|
+
else
|
85
|
+
do_head(n)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def read(key, n=1, at_least=1, timeout=nil)
|
90
|
+
key = time_to_key(Time.now) unless key
|
91
|
+
ary = do_read(key, n)
|
92
|
+
while ary.size < at_least
|
93
|
+
key = ary[-1][0] unless ary.empty?
|
94
|
+
begin
|
95
|
+
renewer = make_renewer(timeout)
|
96
|
+
wait(key, renewer)
|
97
|
+
rescue Rinda::RequestExpiredError
|
98
|
+
return ary
|
99
|
+
end
|
100
|
+
ary += do_read(key, n - ary.size)
|
101
|
+
end
|
102
|
+
ary
|
103
|
+
end
|
104
|
+
|
105
|
+
def read_tag(key, tag, n=1, at_least=1, timeout=nil)
|
106
|
+
at_least = n if n < at_least
|
107
|
+
key = time_to_key(Time.now) unless key
|
108
|
+
ary = do_read_tag(key, tag, n)
|
109
|
+
while ary.size < at_least
|
110
|
+
key = ary[-1][0] unless ary.empty?
|
111
|
+
begin
|
112
|
+
renewer = make_renewer(timeout)
|
113
|
+
wait_tag(key, tag, renewer)
|
114
|
+
rescue Rinda::RequestExpiredError
|
115
|
+
return ary
|
116
|
+
end
|
117
|
+
ary += do_read_tag(key, tag, n - ary.size)
|
118
|
+
end
|
119
|
+
ary
|
120
|
+
end
|
121
|
+
|
122
|
+
def latest?(key, tag=nil)
|
123
|
+
do_latest(key, tag)
|
124
|
+
end
|
125
|
+
|
126
|
+
def older(key, tag=nil)
|
127
|
+
do_older(key, tag)
|
128
|
+
end
|
129
|
+
|
130
|
+
def newer(key, tag=nil)
|
131
|
+
return read(key, 1, 0)[0] unless tag
|
132
|
+
read_tag(key, tag, 1, 0)[0]
|
133
|
+
end
|
134
|
+
|
135
|
+
def tag_next(tag)
|
136
|
+
do_tag_next(tag)
|
137
|
+
end
|
138
|
+
|
139
|
+
def tag_prev(tag)
|
140
|
+
do_tag_prev(tag)
|
141
|
+
end
|
142
|
+
|
143
|
+
private
|
144
|
+
def transaction_rw(key, &blk)
|
145
|
+
_, db = @event.take([key, nil])
|
146
|
+
db.transaction do
|
147
|
+
return yield(db)
|
148
|
+
end
|
149
|
+
ensure
|
150
|
+
@event.write([key, db])
|
151
|
+
end
|
152
|
+
|
153
|
+
def transaction(&blk)
|
154
|
+
transaction_rw(:db, &blk)
|
155
|
+
end
|
156
|
+
|
157
|
+
def transaction_w(&blk)
|
158
|
+
transaction_rw(@w_key, &blk)
|
159
|
+
end
|
160
|
+
|
161
|
+
def from_row(ary)
|
162
|
+
return nil unless ary
|
163
|
+
return ary[0], Marshal.load(ary[1]), ary[2]
|
164
|
+
end
|
165
|
+
|
166
|
+
def do_fetch(key)
|
167
|
+
transaction do |db|
|
168
|
+
db.statement('select value from Drip where key=?').execute(key).each do |row|
|
169
|
+
return Marshal.load(row[0])
|
170
|
+
end
|
171
|
+
end
|
172
|
+
nil
|
173
|
+
end
|
174
|
+
|
175
|
+
def do_tag_next(tag)
|
176
|
+
return nil if tag.nil?
|
177
|
+
transaction do |db|
|
178
|
+
sql = <<SQL
|
179
|
+
select tag from Drip where tag>? order by key asc limit 1
|
180
|
+
SQL
|
181
|
+
db.statement(sql).get_first_value(tag) rescue nil
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
def do_tag_prev(tag)
|
186
|
+
return nil if tag.nil?
|
187
|
+
transaction do |db|
|
188
|
+
sql = <<SQL
|
189
|
+
select tag from Drip where tag<? order by key desc limit 1
|
190
|
+
SQL
|
191
|
+
db.statement(sql).get_first_value(tag) rescue nil
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
def do_head_tag(n, tag)
|
196
|
+
transaction do |db|
|
197
|
+
sql = <<SQL
|
198
|
+
select key, value, tag from Drip where tag=? order by key desc limit ?;
|
199
|
+
SQL
|
200
|
+
db.statement(sql).execute(tag, n).collect {|row| from_row(row)}.reverse
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
def do_read_tag(key, tag, n=1)
|
205
|
+
transaction do |db|
|
206
|
+
sql = <<SQL
|
207
|
+
select key, value, tag from Drip
|
208
|
+
where key > ? and tag=?
|
209
|
+
order by key asc limit ?;
|
210
|
+
SQL
|
211
|
+
db.statement(sql).execute(key, tag, n).collect {|row| from_row(row)}
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
def wait(key, renewer)
|
216
|
+
@event.read([:last, key+1 .. INF], renewer)[1]
|
217
|
+
end
|
218
|
+
|
219
|
+
def wait_tag(key, tag, renewer)
|
220
|
+
@event.read([tag, key+1 .. INF], renewer)[1]
|
221
|
+
end
|
222
|
+
|
223
|
+
def make_renewer(timeout)
|
224
|
+
case timeout
|
225
|
+
when 0
|
226
|
+
return 0
|
227
|
+
when Numeric
|
228
|
+
return Renewer.new(timeout)
|
229
|
+
else
|
230
|
+
nil
|
231
|
+
end
|
232
|
+
end
|
233
|
+
|
234
|
+
def do_head(n)
|
235
|
+
transaction do |db|
|
236
|
+
sql = <<SQL
|
237
|
+
select key, value, tag from Drip order by key desc limit ?
|
238
|
+
SQL
|
239
|
+
db.statement(sql).execute(n).collect {|row| from_row(row)}.reverse
|
240
|
+
end
|
241
|
+
end
|
242
|
+
|
243
|
+
def do_read(key, n)
|
244
|
+
transaction do |db|
|
245
|
+
sql = <<SQL
|
246
|
+
select key, value, tag from Drip where key > ? order by key asc limit ?
|
247
|
+
SQL
|
248
|
+
db.statement(sql).execute(key, n).collect {|row| from_row(row)}
|
249
|
+
end
|
250
|
+
end
|
251
|
+
|
252
|
+
def do_older(key, tag)
|
253
|
+
if key.nil?
|
254
|
+
if tag.nil?
|
255
|
+
return do_head(1)[0]
|
256
|
+
else
|
257
|
+
return do_head_tag(1, tag)[0]
|
258
|
+
end
|
259
|
+
end
|
260
|
+
|
261
|
+
transaction do |db|
|
262
|
+
if tag
|
263
|
+
sql = <<SQL
|
264
|
+
select key, value, tag from Drip where key < ? and tag=?
|
265
|
+
order by key desc limit 1
|
266
|
+
SQL
|
267
|
+
from_row(db.statement(sql).get_first_row(key, tag))
|
268
|
+
else
|
269
|
+
sql = <<SQL
|
270
|
+
select key, value, tag from Drip where key < ?
|
271
|
+
order by key desc limit 1
|
272
|
+
SQL
|
273
|
+
from_row(db.statement(sql).get_first_row(key))
|
274
|
+
end
|
275
|
+
end
|
276
|
+
end
|
277
|
+
|
278
|
+
def make_key(at=Time.now)
|
279
|
+
synchronize do |last|
|
280
|
+
key = [time_to_key(at), last + 1].max
|
281
|
+
yield(key)
|
282
|
+
# key
|
283
|
+
end
|
284
|
+
end
|
285
|
+
|
286
|
+
def make_key_at(at)
|
287
|
+
synchronize do |last|
|
288
|
+
key = time_to_key(at)
|
289
|
+
raise 'InvalidTimeError' if key <= last
|
290
|
+
yield(key)
|
291
|
+
# key
|
292
|
+
end
|
293
|
+
end
|
294
|
+
|
295
|
+
def synchronize
|
296
|
+
_, last = @event.take([:last, nil])
|
297
|
+
last = yield(last)
|
298
|
+
ensure
|
299
|
+
@event.write([:last, last])
|
300
|
+
end
|
301
|
+
|
302
|
+
def do_latest(key, tag)
|
303
|
+
transaction do |db|
|
304
|
+
do_latest_inner(db, key, tag)
|
305
|
+
end
|
306
|
+
end
|
307
|
+
|
308
|
+
def do_latest_inner(db, key, tag)
|
309
|
+
if tag
|
310
|
+
sql = <<SQL
|
311
|
+
select max(key) from Drip where tag=?
|
312
|
+
SQL
|
313
|
+
v = db.statement(sql).get_first_value(tag) || 0
|
314
|
+
else
|
315
|
+
sql = <<SQL
|
316
|
+
select max(key) from Drip
|
317
|
+
SQL
|
318
|
+
v = db.statement(sql).get_first_value() || 0
|
319
|
+
end
|
320
|
+
return v == key
|
321
|
+
end
|
322
|
+
|
323
|
+
def do_write(key, obj, tag, cond=nil)
|
324
|
+
unless tag.nil?
|
325
|
+
raise(ArgumentError) unless String === tag
|
326
|
+
tag = tag.to_s
|
327
|
+
end
|
328
|
+
transaction_w do |db|
|
329
|
+
if cond
|
330
|
+
cond.each {|it|
|
331
|
+
return nil unless do_latest_inner(db, it[1], it[0])
|
332
|
+
}
|
333
|
+
end
|
334
|
+
|
335
|
+
if tag
|
336
|
+
@event.take([tag, nil], 0) rescue nil
|
337
|
+
@event.write([tag, key])
|
338
|
+
end
|
339
|
+
sql = 'insert into Drip values (?, ?, ?)'
|
340
|
+
db.statement(sql).execute(key, Marshal.dump(obj), tag)
|
341
|
+
end
|
342
|
+
key
|
343
|
+
end
|
344
|
+
|
345
|
+
private
|
346
|
+
def create_db(dir)
|
347
|
+
if dir
|
348
|
+
Dir.mkdir(dir) rescue nil
|
349
|
+
# fname = 'file:' + File.join(dir, 'drip.db') + '?cache=shared'
|
350
|
+
fname = File.join(dir, 'drip.db')
|
351
|
+
@w_key = :db
|
352
|
+
@event.write([:db, SQLite3::Database.open(fname)])
|
353
|
+
else
|
354
|
+
fname = ':memory:'
|
355
|
+
@w_key = :db
|
356
|
+
@event.write([:db, SQLite3::Database.open(fname)])
|
357
|
+
end
|
358
|
+
end
|
359
|
+
|
360
|
+
def setup_db(dir)
|
361
|
+
create_db(dir)
|
362
|
+
create_table
|
363
|
+
end
|
364
|
+
|
365
|
+
def create_table
|
366
|
+
transaction_w do |db|
|
367
|
+
begin
|
368
|
+
db.execute('create table Drip (key bigint, value blob, tag text);')
|
369
|
+
db.execute('create index DripKey on Drip(key);')
|
370
|
+
db.execute('create index Tags on Drip(key, tag);')
|
371
|
+
rescue SQLite3::SQLException
|
372
|
+
unless $!.message == 'table Drip already exists'
|
373
|
+
raise $!
|
374
|
+
end
|
375
|
+
end
|
376
|
+
end
|
377
|
+
end
|
378
|
+
|
379
|
+
class Renewer
|
380
|
+
def initialize(timeout)
|
381
|
+
@at = Time.now + timeout
|
382
|
+
end
|
383
|
+
|
384
|
+
def renew
|
385
|
+
@at - Time.now
|
386
|
+
end
|
387
|
+
end
|
388
|
+
end
|
389
|
+
|
390
|
+
if __FILE__ == $0
|
391
|
+
# d3 = Drip3.new('test_db')
|
392
|
+
d3 = Drip3.new(nil)
|
393
|
+
|
394
|
+
d3.write("こんにちはせかい\0\0こんにちはアゲイン")
|
395
|
+
p d3.head[0][1]
|
396
|
+
|
397
|
+
key = d3.write('start')
|
398
|
+
50.times do |n|
|
399
|
+
Thread.new(n) do |x|
|
400
|
+
100.times do
|
401
|
+
d3.write(x, 'count')
|
402
|
+
end
|
403
|
+
d3.write(x, 'wakeup')
|
404
|
+
end
|
405
|
+
end
|
406
|
+
50.times do
|
407
|
+
key, value, = d3.read_tag(key, 'wakeup', 1)[0]
|
408
|
+
p value
|
409
|
+
end
|
410
|
+
end
|
data/test/basic3.rb
ADDED
@@ -0,0 +1,250 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require '../lib/drip3.rb'
|
3
|
+
require 'fileutils'
|
4
|
+
|
5
|
+
class TestDrip < Test::Unit::TestCase
|
6
|
+
def setup
|
7
|
+
@drip = Drip3.new(nil)
|
8
|
+
end
|
9
|
+
|
10
|
+
def test_time_travel
|
11
|
+
@drip.write('age' => 1)
|
12
|
+
@drip.write('age' => 2)
|
13
|
+
@drip.write('age' => 3)
|
14
|
+
oid, value = @drip.older(nil)
|
15
|
+
assert_equal(value, 'age' => 3)
|
16
|
+
oid, value = @drip.older(oid)
|
17
|
+
assert_equal(value, 'age' => 2)
|
18
|
+
oid, value = @drip.older(oid)
|
19
|
+
assert_equal(value, 'age' => 1)
|
20
|
+
oid, value = @drip.older(oid)
|
21
|
+
assert_equal(oid, nil)
|
22
|
+
assert_equal(value, nil)
|
23
|
+
|
24
|
+
oid, value = @drip.newer(0)
|
25
|
+
assert_equal(value, 'age' => 1)
|
26
|
+
oid, value = @drip.newer(oid)
|
27
|
+
assert_equal(value, 'age' => 2)
|
28
|
+
oid, value = @drip.newer(oid)
|
29
|
+
assert_equal(value, 'age' => 3)
|
30
|
+
oid, value = @drip.newer(oid)
|
31
|
+
assert_equal(oid, nil)
|
32
|
+
assert_equal(value, nil)
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_read
|
36
|
+
11.times do |n|
|
37
|
+
@drip.write("n=#{n}" => 'x' * n, n => n, "n" => n, :symbol => n)
|
38
|
+
end
|
39
|
+
ary = @drip.read(0, 3)
|
40
|
+
assert_equal(ary.size, 3)
|
41
|
+
assert_equal(ary[0][1]['n'], 0)
|
42
|
+
assert_equal(ary[1][1]['n'], 1)
|
43
|
+
assert_equal(ary[2][1]['n'], 2)
|
44
|
+
ary = @drip.read(ary[2][0], 3)
|
45
|
+
assert_equal(ary.size, 3)
|
46
|
+
ary = @drip.read(ary[2][0], 3)
|
47
|
+
assert_equal(ary.size, 3)
|
48
|
+
ary = @drip.read(ary[2][0], 3)
|
49
|
+
assert_equal(ary.size, 2)
|
50
|
+
|
51
|
+
oid = @drip.write('latest', 'tag1')
|
52
|
+
oid, value, *tags = @drip.newer(oid - 1)
|
53
|
+
assert_equal(value, 'latest')
|
54
|
+
assert_equal(tags, ['tag1'])
|
55
|
+
end
|
56
|
+
|
57
|
+
def test_symbol_is_not_tag
|
58
|
+
assert_raise(ArgumentError){
|
59
|
+
@drip.write({:symbol => :symbol, 'string' => :string}, :symbol)
|
60
|
+
}
|
61
|
+
end
|
62
|
+
|
63
|
+
def test_number_is_not_tag
|
64
|
+
assert_raise(ArgumentError){
|
65
|
+
@drip.write({5 => :five, 'string' => :string}, 5)
|
66
|
+
}
|
67
|
+
end
|
68
|
+
|
69
|
+
def test_older_now_is_newest
|
70
|
+
@drip.write('age' => 1)
|
71
|
+
@drip.write('age' => 2)
|
72
|
+
@drip.write('age' => 3)
|
73
|
+
oid, value, = @drip.older(nil)
|
74
|
+
assert_equal(value, 'age' => 3)
|
75
|
+
oid, value, = @drip.older(@drip.time_to_key(Time.now))
|
76
|
+
assert_equal(value, 'age' => 3)
|
77
|
+
|
78
|
+
# newer(past)
|
79
|
+
assert_equal(@drip.newer(0)[1], 'age' => 1)
|
80
|
+
assert_equal(@drip.newer(0)[1], 'age' => 1)
|
81
|
+
end
|
82
|
+
|
83
|
+
def test_read_tag
|
84
|
+
3.times do |n|
|
85
|
+
@drip.write({'n' => n}, 'n')
|
86
|
+
@drip.write({'n' => n, '2' => n * 2}, 'n')
|
87
|
+
@drip.write({'n' => n, '2' => n * 2, '3' => n * 3}, 'n')
|
88
|
+
end
|
89
|
+
|
90
|
+
ary = @drip.read_tag(0, 'n', 10)
|
91
|
+
assert_equal(ary.size, 9)
|
92
|
+
assert_equal(ary[0][1]['n'], 0)
|
93
|
+
assert_equal(ary[0][2], 'n')
|
94
|
+
end
|
95
|
+
|
96
|
+
def test_head
|
97
|
+
10.times do |n|
|
98
|
+
@drip.write(n)
|
99
|
+
end
|
100
|
+
|
101
|
+
ary = @drip.head(3)
|
102
|
+
assert_equal(ary.size, 3)
|
103
|
+
assert_equal(ary[0][1], 7)
|
104
|
+
assert_equal(ary[2][1], 9)
|
105
|
+
end
|
106
|
+
|
107
|
+
def test_after
|
108
|
+
assert_equal(@drip.write_after(Time.at(1), 1), 1000000)
|
109
|
+
assert_equal(@drip.write_after(Time.at(2), 2), 2000000)
|
110
|
+
assert_equal(@drip.write_after(Time.at(3), 3), 3000000)
|
111
|
+
assert_equal(@drip.write_after(Time.at(4), 4), 4000000)
|
112
|
+
assert_equal(@drip.write_after(Time.at(4), 5), 4000001)
|
113
|
+
assert_equal(@drip.write_after(Time.at(2), 6), 4000002)
|
114
|
+
assert_equal(@drip.write_after(Time.at(5), 6), 5000000)
|
115
|
+
assert_equal(@drip.write_after(Time.at(5), 7), 5000001)
|
116
|
+
assert_equal(@drip.write_at(Time.at(6), 8), 6000000)
|
117
|
+
assert_raise(RuntimeError) {@drip.write_at(Time.at(6), 8)}
|
118
|
+
assert_equal(@drip.write_after(Time.at(5), 8), 6000001)
|
119
|
+
end
|
120
|
+
|
121
|
+
def test_use_string_tag
|
122
|
+
oid = @drip.write(:symbol, 'dup')
|
123
|
+
assert_equal(@drip[oid], :symbol)
|
124
|
+
end
|
125
|
+
|
126
|
+
def test_latest?
|
127
|
+
key = @drip.write(:start)
|
128
|
+
|
129
|
+
assert_equal(@drip.latest?(key), true)
|
130
|
+
|
131
|
+
10.times do |n|
|
132
|
+
@drip.write(n)
|
133
|
+
end
|
134
|
+
assert_equal(@drip.latest?(key), false)
|
135
|
+
key = @drip.write(:stop)
|
136
|
+
assert_equal(@drip.latest?(key), true)
|
137
|
+
|
138
|
+
key = @drip.write(:tag_start, 'tag')
|
139
|
+
@drip.write(:tag, 'ignore tag')
|
140
|
+
assert_equal(@drip.latest?(key, 'tag'), true)
|
141
|
+
@drip.write(:tag, 'tag')
|
142
|
+
assert_equal(@drip.latest?(key, 'tag'), false)
|
143
|
+
end
|
144
|
+
|
145
|
+
def test_write_if_latest
|
146
|
+
t1 = @drip.write('t1', 't1')
|
147
|
+
t2 = @drip.write('t2', 't2')
|
148
|
+
t3 = @drip.write('t3', 't3')
|
149
|
+
assert_equal(@drip.latest?(t1, 't1'), true)
|
150
|
+
assert(@drip.write_if_latest([['t1', t1],
|
151
|
+
['t2', t2],
|
152
|
+
['t3', t3],
|
153
|
+
['t4', 0]], 'hello', 't1'))
|
154
|
+
assert_equal(@drip.latest?(t1, 't1'), false)
|
155
|
+
assert_equal(@drip.write_if_latest([['t1', t1],
|
156
|
+
['t2', t2],
|
157
|
+
['t3', t3]], 'hello', 't1'), nil)
|
158
|
+
end
|
159
|
+
|
160
|
+
end
|
161
|
+
|
162
|
+
class TestDripUsingStorage < TestDrip
|
163
|
+
def remove_drip(dir='test_db')
|
164
|
+
FileUtils.rm_r(dir, :force => true)
|
165
|
+
end
|
166
|
+
|
167
|
+
def setup
|
168
|
+
remove_drip
|
169
|
+
@drip = Drip3.new('test_db')
|
170
|
+
end
|
171
|
+
|
172
|
+
def teardown
|
173
|
+
remove_drip
|
174
|
+
end
|
175
|
+
|
176
|
+
def test_tag_browse
|
177
|
+
@drip.write(1, 't1')
|
178
|
+
@drip.write(2, 't2')
|
179
|
+
@drip.write(3, 't3')
|
180
|
+
@drip.write(4, 't4')
|
181
|
+
|
182
|
+
assert_equal(@drip.tag_next(''), 't1')
|
183
|
+
assert_equal(@drip.tag_next('t1'), 't2')
|
184
|
+
assert_equal(@drip.tag_next('t3'), 't4')
|
185
|
+
assert_equal(@drip.tag_next('t5'), nil)
|
186
|
+
|
187
|
+
assert_equal(@drip.tag_prev('u'), 't4')
|
188
|
+
assert_equal(@drip.tag_prev('t2'), 't1')
|
189
|
+
assert_equal(@drip.tag_prev('t1'), nil)
|
190
|
+
end
|
191
|
+
|
192
|
+
def test_twice_latest?
|
193
|
+
assert_equal(@drip.latest?(1), false)
|
194
|
+
tag1 = @drip.write('tag1', 'tag1')
|
195
|
+
assert_equal(@drip.latest?(tag1), true)
|
196
|
+
@drip.write('nop', 'tag1')
|
197
|
+
@drip.write('nop', 'tag1')
|
198
|
+
tag2 = @drip.write('tag2', 'tag1')
|
199
|
+
assert_equal(@drip.latest?(1), false)
|
200
|
+
drip = Drip3.new('test_db')
|
201
|
+
assert_equal(drip.latest?(1), false)
|
202
|
+
assert_equal(drip.latest?(tag1, 'tag1'), false)
|
203
|
+
assert_equal(drip.latest?(tag2, 'tag1'), true)
|
204
|
+
assert_equal(drip.latest?(tag2, 'tag0'), false)
|
205
|
+
end
|
206
|
+
|
207
|
+
def test_twice
|
208
|
+
11.times do |n|
|
209
|
+
@drip.write("n=#{n}" => 'x' * n, n => n, "n" => n, :symbol => n)
|
210
|
+
end
|
211
|
+
|
212
|
+
drip = Drip3.new('test_db')
|
213
|
+
ary = drip.head(3)
|
214
|
+
assert_equal(ary.size, 3)
|
215
|
+
assert_equal(ary[0][1]['n'], 8)
|
216
|
+
assert_equal(ary[1][1]['n'], 9)
|
217
|
+
assert_equal(ary[2][1]['n'], 10)
|
218
|
+
ary = drip.head(1)
|
219
|
+
assert_equal(ary.size, 1)
|
220
|
+
assert_equal(ary[0][1]['n'], 10)
|
221
|
+
ary = drip.read(0, 3)
|
222
|
+
assert_equal(ary.size, 3)
|
223
|
+
assert_equal(ary[0][1]['n'], 0)
|
224
|
+
assert_equal(ary[1][1]['n'], 1)
|
225
|
+
assert_equal(ary[2][1]['n'], 2)
|
226
|
+
ary = drip.read(ary[2][0], 3)
|
227
|
+
assert_equal(ary.size, 3)
|
228
|
+
ary = drip.read(ary[2][0], 3)
|
229
|
+
assert_equal(ary.size, 3)
|
230
|
+
ary = drip.read(ary[2][0], 3)
|
231
|
+
assert_equal(ary.size, 2)
|
232
|
+
end
|
233
|
+
|
234
|
+
def test_huge
|
235
|
+
str = File.read(__FILE__)
|
236
|
+
|
237
|
+
10.times do
|
238
|
+
Thread.new do
|
239
|
+
1000.times do |n|
|
240
|
+
@drip.write(str, "n=#{n}")
|
241
|
+
end
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
assert_equal(@drip.read_tag(0, 'n=999', 10, 10).size, 10)
|
246
|
+
|
247
|
+
assert_equal(10000, @drip.read(0, 12000, 10000).size)
|
248
|
+
end
|
249
|
+
end
|
250
|
+
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: drip
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Masatoshi Seki
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2018-09-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rbtree
|
@@ -24,6 +24,34 @@ dependencies:
|
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: test-unit
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: sqlite3
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
27
55
|
description: ''
|
28
56
|
email:
|
29
57
|
executables: []
|
@@ -39,6 +67,7 @@ files:
|
|
39
67
|
- install.rb
|
40
68
|
- lib/drip.rb
|
41
69
|
- lib/drip/version.rb
|
70
|
+
- lib/drip3.rb
|
42
71
|
- lib/my_drip.rb
|
43
72
|
- sample/copocopo.rb
|
44
73
|
- sample/demo4book/crawl.rb
|
@@ -54,6 +83,7 @@ files:
|
|
54
83
|
- sample/simple-oauth.rb
|
55
84
|
- sample/tw_markov.rb
|
56
85
|
- test/basic.rb
|
86
|
+
- test/basic3.rb
|
57
87
|
homepage: https://github.com/seki/Drip
|
58
88
|
licenses: []
|
59
89
|
metadata: {}
|
@@ -73,9 +103,10 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
73
103
|
version: '0'
|
74
104
|
requirements: []
|
75
105
|
rubyforge_project: drip
|
76
|
-
rubygems_version: 2.
|
106
|
+
rubygems_version: 2.7.7
|
77
107
|
signing_key:
|
78
108
|
specification_version: 4
|
79
109
|
summary: Simple RD-Stream for Rinda::TupleSpace lovers.
|
80
110
|
test_files:
|
81
111
|
- test/basic.rb
|
112
|
+
- test/basic3.rb
|