threadsafe-lru 0.0.2 → 0.0.3
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.
- data/.rspec +1 -0
- data/lib/threadsafe-lru.rb +1 -0
- data/lib/threadsafe-lru/DoubleLinkedList.rb +69 -3
- data/lib/threadsafe-lru/ThreadSafeLruCache.rb +16 -13
- data/lib/threadsafe-lru/version.rb +1 -1
- data/spec/threadsafe-lru/DoubleLinkedList_spec.rb +77 -0
- metadata +25 -23
- data/autotest/discover.rb +0 -1
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/lib/threadsafe-lru.rb
CHANGED
@@ -1,6 +1,72 @@
|
|
1
|
-
module ThreadSafeLru
|
1
|
+
module ThreadSafeLru
|
2
|
+
class ListNode
|
3
|
+
def initialize value
|
4
|
+
@value=value
|
5
|
+
end
|
6
|
+
|
7
|
+
def insert_between prev_node, next_node
|
8
|
+
self.next=next_node
|
9
|
+
self.prev=prev_node
|
10
|
+
prev_node.next=self
|
11
|
+
next_node.prev=self
|
12
|
+
self
|
13
|
+
end
|
14
|
+
|
15
|
+
def remove
|
16
|
+
self.prev.next=self.next
|
17
|
+
self.next.prev=self.prev
|
18
|
+
self.next=nil
|
19
|
+
self.prev=nil
|
20
|
+
end
|
21
|
+
|
22
|
+
attr_reader :value
|
23
|
+
attr_accessor :next
|
24
|
+
attr_accessor :prev
|
25
|
+
|
26
|
+
end
|
27
|
+
|
2
28
|
class DoubleLinkedList
|
3
|
-
|
4
|
-
|
29
|
+
|
30
|
+
def initialize
|
31
|
+
@head=ListNode.new "head"
|
32
|
+
@tail=ListNode.new "tail"
|
33
|
+
@head.next=@tail
|
34
|
+
@tail.prev=@head
|
35
|
+
end
|
36
|
+
|
37
|
+
|
38
|
+
def add_to_head value
|
39
|
+
new_node=ListNode.new value
|
40
|
+
new_node.insert_between @head,@head.next
|
41
|
+
new_node
|
42
|
+
end
|
43
|
+
|
44
|
+
def bump_to_top node
|
45
|
+
node.remove
|
46
|
+
node.insert_between @head,@head.next
|
47
|
+
end
|
48
|
+
|
49
|
+
def remove_last
|
50
|
+
node=@tail.prev
|
51
|
+
node.remove
|
52
|
+
node
|
53
|
+
end
|
54
|
+
|
55
|
+
def clear
|
56
|
+
@head.next=@tail
|
57
|
+
@tail.prev=@head
|
58
|
+
end
|
59
|
+
|
60
|
+
|
61
|
+
def to_a
|
62
|
+
result=[]
|
63
|
+
current=@head.next
|
64
|
+
while current != @tail
|
65
|
+
result << current.value
|
66
|
+
current=current.next
|
67
|
+
end
|
68
|
+
result
|
69
|
+
end
|
70
|
+
|
5
71
|
end
|
6
72
|
end
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'thread'
|
2
|
+
require 'threadsafe-lru/DoubleLinkedList'
|
2
3
|
|
3
4
|
module ThreadSafeLru
|
4
5
|
class LruCache
|
@@ -6,19 +7,20 @@ module ThreadSafeLru
|
|
6
7
|
@size=size
|
7
8
|
@cached_values={}
|
8
9
|
@factory_block=block
|
9
|
-
@recently_used=
|
10
|
+
@recently_used=ThreadSafeLru::DoubleLinkedList.new
|
10
11
|
@lock=Mutex.new
|
11
12
|
end
|
12
13
|
|
13
14
|
def size
|
14
|
-
@
|
15
|
+
@cached_values.size
|
15
16
|
end
|
16
17
|
|
17
18
|
|
18
19
|
def drop key
|
19
20
|
@lock.synchronize do
|
20
|
-
|
21
|
-
|
21
|
+
node=@cached_values.delete key
|
22
|
+
node.remove if node
|
23
|
+
|
22
24
|
end
|
23
25
|
end
|
24
26
|
|
@@ -42,19 +44,18 @@ module ThreadSafeLru
|
|
42
44
|
|
43
45
|
def get_node key
|
44
46
|
if @cached_values.has_key?(key)
|
45
|
-
|
46
|
-
@recently_used
|
47
|
+
dll_node=@cached_values[key]
|
48
|
+
@recently_used.bump_to_top dll_node
|
47
49
|
else
|
48
|
-
while (
|
49
|
-
dropped=@recently_used.
|
50
|
-
@cached_values.delete(dropped)
|
50
|
+
while (size >= @size) do
|
51
|
+
dropped=@recently_used.remove_last
|
52
|
+
@cached_values.delete(dropped.value.key)
|
51
53
|
end
|
52
54
|
node=Node.new key
|
53
|
-
|
54
|
-
@
|
55
|
+
dll_node=@recently_used.add_to_head node
|
56
|
+
@cached_values[key]=dll_node
|
55
57
|
end
|
56
|
-
|
57
|
-
@cached_values[key]
|
58
|
+
@cached_values[key].value
|
58
59
|
end
|
59
60
|
|
60
61
|
end
|
@@ -67,6 +68,8 @@ module ThreadSafeLru
|
|
67
68
|
@lock=Mutex.new
|
68
69
|
end
|
69
70
|
|
71
|
+
attr_reader :key
|
72
|
+
|
70
73
|
def get_value block
|
71
74
|
@lock.synchronize do
|
72
75
|
unless (@produced)
|
@@ -0,0 +1,77 @@
|
|
1
|
+
require 'threadsafe-lru'
|
2
|
+
|
3
|
+
module ThreadSafeLru
|
4
|
+
describe DoubleLinkedList do
|
5
|
+
|
6
|
+
describe :clear do
|
7
|
+
it "should clear all values" do
|
8
|
+
subject.add_to_head("value1")
|
9
|
+
subject.clear
|
10
|
+
subject.to_a.should == []
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
describe :add_to_head do
|
15
|
+
it "should append node to head" do
|
16
|
+
subject.add_to_head("value1").should be_a ListNode
|
17
|
+
subject.to_a.should == ["value1"]
|
18
|
+
subject.add_to_head("value0").should be_a ListNode
|
19
|
+
subject.to_a.should == ["value0","value1"]
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe :remove_last do
|
24
|
+
it "should remove last element from the linked list" do
|
25
|
+
subject.add_to_head("v1")
|
26
|
+
subject.add_to_head("v2")
|
27
|
+
subject.remove_last
|
28
|
+
subject.to_a.should == ["v2"]
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe :bump_to_top do
|
33
|
+
it "should move node to the top of the list" do
|
34
|
+
last=subject.add_to_head("v1")
|
35
|
+
first=subject.add_to_head("v2")
|
36
|
+
subject.bump_to_top last
|
37
|
+
subject.to_a.should == ["v1","v2"]
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
describe ListNode do
|
43
|
+
subject {ListNode.new "value"}
|
44
|
+
|
45
|
+
describe :insert_between do
|
46
|
+
let(:prev_node) {ListNode.new "prev"}
|
47
|
+
let(:next_node) {ListNode.new "next"}
|
48
|
+
|
49
|
+
it "should insert node in the chain between prev and next" do
|
50
|
+
subject.insert_between(prev_node,next_node)
|
51
|
+
subject.prev.should == prev_node
|
52
|
+
subject.next.should == next_node
|
53
|
+
prev_node.next.should == subject
|
54
|
+
next_node.prev.should == subject
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
describe :remove do
|
59
|
+
let(:prev_node) {ListNode.new "prev"}
|
60
|
+
let(:next_node) {ListNode.new "next"}
|
61
|
+
it "should remove itself from the chain" do
|
62
|
+
subject.insert_between prev_node, next_node
|
63
|
+
subject.remove
|
64
|
+
subject.next.should == nil
|
65
|
+
subject.prev.should == nil
|
66
|
+
|
67
|
+
prev_node.next.should == next_node
|
68
|
+
next_node.prev.should == prev_node
|
69
|
+
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
74
|
+
|
75
|
+
|
76
|
+
|
77
|
+
end
|
metadata
CHANGED
@@ -1,49 +1,50 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: threadsafe-lru
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
|
5
|
-
|
4
|
+
version: 0.0.3
|
5
|
+
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Dragan Milic
|
9
|
-
autorequire:
|
9
|
+
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2013-04-29 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rspec
|
16
|
-
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
17
18
|
requirements:
|
18
19
|
- - ! '>='
|
19
20
|
- !ruby/object:Gem::Version
|
20
21
|
version: '0'
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
21
25
|
none: false
|
22
|
-
requirement: !ruby/object:Gem::Requirement
|
23
26
|
requirements:
|
24
27
|
- - ! '>='
|
25
28
|
- !ruby/object:Gem::Version
|
26
29
|
version: '0'
|
27
|
-
none: false
|
28
|
-
prerelease: false
|
29
|
-
type: :development
|
30
30
|
- !ruby/object:Gem::Dependency
|
31
31
|
name: autotest
|
32
|
-
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
33
34
|
requirements:
|
34
35
|
- - ! '>='
|
35
36
|
- !ruby/object:Gem::Version
|
36
37
|
version: '0'
|
38
|
+
type: :development
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
41
|
none: false
|
38
|
-
requirement: !ruby/object:Gem::Requirement
|
39
42
|
requirements:
|
40
43
|
- - ! '>='
|
41
44
|
- !ruby/object:Gem::Version
|
42
45
|
version: '0'
|
43
|
-
|
44
|
-
|
45
|
-
type: :development
|
46
|
-
description: Thread safe implemenation of in-memory LRU cache compatible with Java Memory Model
|
46
|
+
description: Thread safe implemenation of in-memory LRU cache compatible with Java
|
47
|
+
Memory Model
|
47
48
|
email:
|
48
49
|
- dragan@netice9.com
|
49
50
|
executables: []
|
@@ -52,39 +53,40 @@ extra_rdoc_files: []
|
|
52
53
|
files:
|
53
54
|
- .gitignore
|
54
55
|
- .project
|
56
|
+
- .rspec
|
55
57
|
- LICENSE
|
56
58
|
- README.md
|
57
|
-
- autotest/discover.rb
|
58
59
|
- lib/threadsafe-lru.rb
|
59
60
|
- lib/threadsafe-lru/DoubleLinkedList.rb
|
60
61
|
- lib/threadsafe-lru/ThreadSafeLruCache.rb
|
61
62
|
- lib/threadsafe-lru/version.rb
|
63
|
+
- spec/threadsafe-lru/DoubleLinkedList_spec.rb
|
62
64
|
- spec/threadsafe-lru/ThreadSafeLruCache_spec.rb
|
63
65
|
- threadsafe-lru.gemspec
|
64
66
|
homepage: https://github.com/draganm/threadsafe-lru
|
65
67
|
licenses: []
|
66
|
-
post_install_message:
|
68
|
+
post_install_message:
|
67
69
|
rdoc_options: []
|
68
70
|
require_paths:
|
69
71
|
- lib
|
70
72
|
required_ruby_version: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
71
74
|
requirements:
|
72
75
|
- - ! '>='
|
73
76
|
- !ruby/object:Gem::Version
|
74
77
|
version: '0'
|
75
|
-
none: false
|
76
78
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
79
|
+
none: false
|
77
80
|
requirements:
|
78
81
|
- - ! '>='
|
79
82
|
- !ruby/object:Gem::Version
|
80
83
|
version: '0'
|
81
|
-
none: false
|
82
84
|
requirements: []
|
83
|
-
rubyforge_project:
|
84
|
-
rubygems_version: 1.8.
|
85
|
-
signing_key:
|
85
|
+
rubyforge_project:
|
86
|
+
rubygems_version: 1.8.25
|
87
|
+
signing_key:
|
86
88
|
specification_version: 3
|
87
89
|
summary: Thread safe in memory LRU cache
|
88
90
|
test_files:
|
91
|
+
- spec/threadsafe-lru/DoubleLinkedList_spec.rb
|
89
92
|
- spec/threadsafe-lru/ThreadSafeLruCache_spec.rb
|
90
|
-
...
|
data/autotest/discover.rb
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
Autotest.add_discovery {"rspec2"}
|