lockfile 1.1.0 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
data/samples/a.rb DELETED
@@ -1,112 +0,0 @@
1
- #!/usr/bin/env ruby
2
- $:.unshift '../lib'
3
- #
4
- # puts this script in an nfs located directory and run from a couple of nodes at
5
- # once. the list should appear ordered from either host - note that times may
6
- # not be ordered depending on the system clocks
7
- #
8
-
9
- #
10
- # builtin
11
- #
12
- require 'socket'
13
- require 'pstore'
14
- #
15
- # do what we can to invalidate any nfs caching
16
- #
17
- def timestamp time = Time.now
18
- #{{{
19
- usec = "#{ time.usec }"
20
- usec << ('0' * (6 - usec.size)) if usec.size < 6
21
- time.strftime('%Y-%m-%d %H:%M:%S.') << usec
22
- #}}}
23
- end
24
- def hostname
25
- #{{{
26
- @__hostname__ ||= Socket::gethostname
27
- #}}}
28
- end
29
- def tmpnam dir = Dir.tmpdir, seed = File.basename($0)
30
- #{{{
31
- pid = Process.pid
32
- path = "%s_%s_%s_%s_%d" %
33
- [hostname, seed, pid, timestamp.gsub(/\s+/o,'_'), rand(101010)]
34
- File.join(dir, path)
35
- #}}}
36
- end
37
- def uncache file
38
- #{{{
39
- refresh = nil
40
- begin
41
- is_a_file = File === file
42
- path = (is_a_file ? file.path : file.to_s)
43
- stat = (is_a_file ? file.stat : File.stat(file.to_s))
44
- refresh = tmpnam(File.dirname(path))
45
- File.link path, refresh rescue File.symlink path, refresh
46
- File.chmod stat.mode, path
47
- File.utime stat.atime, stat.mtime, path
48
- ensure
49
- begin
50
- File.unlink refresh if refresh
51
- rescue Errno::ENOENT
52
- end
53
- end
54
- #}}}
55
- end
56
- #
57
- # raa - http://raa.ruby-lang.org/project/lockfile/
58
- #
59
- require 'lockfile'
60
- pstore = PStore.new 'test.db'
61
- timeout = 60
62
- max_age = 8
63
- refresh = 2
64
- debug = false
65
- lockfile = Lockfile.new 'test.lock',
66
- :timeout => timeout,
67
- :max_age => max_age,
68
- :refresh => refresh,
69
- :debug => debug
70
- #
71
- # flock throws ENOLCK on nfs file systems in newer linux kernels
72
- # plus we want to show that lockfile alone can do the locking
73
- #
74
- class File
75
- def flock(*args,&block);true;end
76
- end
77
- #
78
- # if locking does not work this loop will blow up (Marshal load error) or appear
79
- # un-ordered. actually it will eventually blow up due to nfs caching - but that
80
- # is not the fault of the lockfile class! for the most part it is a simply demo
81
- # of locking. the file will never become corrupt, it just will be unreadable at
82
- # times due to kernel caching.
83
- #
84
- loop do
85
- lockfile.lock do
86
- uncache pstore.path
87
- pstore.transaction do
88
- #
89
- # get/update list
90
- #
91
- pstore[:list] = [] unless pstore.root? :list
92
- list = pstore[:list]
93
- tuple = [list.size, hostname, Time.now.to_f]
94
- list << tuple
95
- #
96
- # show last 16 elements
97
- #
98
- puts '---'
99
- list[-([list.size, 16].min)..-1].each{|tuple| p tuple}
100
- puts '---'
101
- #
102
- # keep it a reasonable size
103
- #
104
- list.shift while list.size > 1024
105
- #
106
- # write back updates
107
- #
108
- pstore[:list] = list
109
- end
110
- end
111
- sleep 1
112
- end
data/samples/nfsstore.rb DELETED
@@ -1,203 +0,0 @@
1
- #
2
- # How to use:
3
- #
4
- # db = NFSStore.new("/tmp/foo")
5
- # db.transaction do
6
- # p db.roots
7
- # ary = db["root"] = [1,2,3,4]
8
- # ary[0] = [1,1.5]
9
- # end
10
-
11
- # db.transaction do
12
- # p db["root"]
13
- # end
14
-
15
- require "ftools"
16
- require "digest/md5"
17
- require "socket"
18
-
19
- require 'lockfile'
20
-
21
- class NFSStore
22
- HOSTNAME = Socket::gethostname
23
- class Error < StandardError
24
- end
25
-
26
- def initialize(file)
27
- dir = File::dirname(file)
28
- unless File::directory? dir
29
- raise NFSStore::Error, format("directory %s does not exist", dir)
30
- end
31
- if File::exist? file and not File::readable? file
32
- raise NFSStore::Error, format("file %s not readable", file)
33
- end
34
- @transaction = false
35
- @filename = file
36
- @lockfile = Lockfile.new "#{ @filename }.lock",:max_age=>64,:refresh=>8
37
- @abort = false
38
- end
39
-
40
- def in_transaction
41
- raise NFSStore::Error, "not in transaction" unless @transaction
42
- end
43
- private :in_transaction
44
-
45
- def [](name)
46
- in_transaction
47
- @table[name]
48
- end
49
- def fetch(name, default=NFSStore::Error)
50
- unless @table.key? name
51
- if default==NFSStore::Error
52
- raise NFSStore::Error, format("undefined root name `%s'", name)
53
- else
54
- default
55
- end
56
- end
57
- self[name]
58
- end
59
- def []=(name, value)
60
- in_transaction
61
- @table[name] = value
62
- end
63
- def delete(name)
64
- in_transaction
65
- @table.delete name
66
- end
67
- def roots
68
- in_transaction
69
- @table.keys
70
- end
71
- def root?(name)
72
- in_transaction
73
- @table.key? name
74
- end
75
- def path
76
- @filename
77
- end
78
- def commit
79
- in_transaction
80
- @abort = false
81
- throw :pstore_abort_transaction
82
- end
83
- def abort
84
- in_transaction
85
- @abort = true
86
- throw :pstore_abort_transaction
87
- end
88
-
89
- # do what we can to invalidate any nfs caching
90
- def uncache file
91
- begin
92
- stat = file.stat
93
- path = file.path
94
- refresh = "%s.%s.%s.%s" % [path, HOSTNAME, $$, Time.now.to_i % 1024]
95
- File.link path, refresh
96
- file.chmod stat.mode
97
- File.utime stat.atime, stat.mtime, path
98
- rescue Exception => e
99
- warn e
100
- ensure
101
- begin
102
- File.unlink refresh if File.exist? refresh
103
- rescue Exception => e
104
- warn e
105
- end
106
- end
107
- end
108
-
109
-
110
- def transaction(read_only=false)
111
- raise NFSStore::Error, "nested transaction" if @transaction
112
- file = nil
113
- value = nil
114
-
115
- @lockfile.lock do
116
- begin
117
- @transaction = true
118
- backup = @filename+"~"
119
- begin
120
- file = File::open(@filename, read_only ? "rb" : "rb+")
121
- orig = true
122
- rescue Errno::ENOENT
123
- raise if read_only
124
- file = File::open(@filename, "wb+")
125
- end
126
- #file.flock(read_only ? File::LOCK_SH : File::LOCK_EX)
127
- uncache file
128
- file.rewind
129
- if read_only
130
- @table = Marshal::load(file)
131
- elsif orig and (content = file.read) != ""
132
- @table = Marshal::load(content)
133
- size = content.size
134
- md5 = Digest::MD5.digest(content)
135
- content = nil # unreference huge data
136
- else
137
- @table = {}
138
- end
139
- begin
140
- catch(:pstore_abort_transaction) do
141
- value = yield(self)
142
- end
143
- rescue Exception
144
- @abort = true
145
- raise
146
- ensure
147
- if !read_only and !@abort
148
- file.rewind
149
- content = Marshal::dump(@table)
150
- if !md5 || size != content.size || md5 != Digest::MD5.digest(content)
151
- File::copy @filename, backup
152
- begin
153
- file.write(content)
154
- file.truncate(file.pos)
155
- content = nil # unreference huge data
156
- rescue
157
- File::rename backup, @filename if File::exist?(backup)
158
- raise
159
- end
160
- end
161
- end
162
- if @abort and !orig
163
- File.unlink(@filename)
164
- end
165
- @abort = false
166
- end
167
- ensure
168
- @table = nil
169
- @transaction = false
170
- file.close if file
171
- end
172
- end
173
- value
174
- end
175
- end
176
-
177
-
178
-
179
-
180
-
181
-
182
-
183
-
184
-
185
- if __FILE__ == $0
186
- db = NFSStore.new("/tmp/foo")
187
- db.transaction do
188
- p db.roots
189
- ary = db["root"] = [1,2,3,4]
190
- ary[1] = [1,1.5]
191
- end
192
-
193
- 1000.times do
194
- db.transaction do
195
- db["root"][0] += 1
196
- p db["root"][0]
197
- end
198
- end
199
-
200
- db.transaction(true) do
201
- p db["root"]
202
- end
203
- end
data/samples/test.db DELETED
Binary file
data/samples/test.db~ DELETED
Binary file