arrow 1.0.7
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/ChangeLog +1590 -0
- data/LICENSE +28 -0
- data/README +75 -0
- data/Rakefile +366 -0
- data/Rakefile.local +63 -0
- data/data/arrow/applets/TEMPLATE.rb.tpl +53 -0
- data/data/arrow/applets/args.rb +50 -0
- data/data/arrow/applets/config.rb +55 -0
- data/data/arrow/applets/error.rb +63 -0
- data/data/arrow/applets/files.rb +46 -0
- data/data/arrow/applets/inspect.rb +46 -0
- data/data/arrow/applets/nosuchapplet.rb +31 -0
- data/data/arrow/applets/status.rb +92 -0
- data/data/arrow/applets/test.rb +133 -0
- data/data/arrow/applets/tutorial/counter.rb +96 -0
- data/data/arrow/applets/tutorial/dingus.rb +67 -0
- data/data/arrow/applets/tutorial/hello.rb +34 -0
- data/data/arrow/applets/tutorial/hello2.rb +73 -0
- data/data/arrow/applets/tutorial/imgtext.rb +90 -0
- data/data/arrow/applets/tutorial/imgtext2.rb +286 -0
- data/data/arrow/applets/tutorial/index.rb +36 -0
- data/data/arrow/applets/tutorial/logo.rb +98 -0
- data/data/arrow/applets/tutorial/memcache.rb +61 -0
- data/data/arrow/applets/tutorial/missing.rb +37 -0
- data/data/arrow/applets/tutorial/protected.rb +100 -0
- data/data/arrow/applets/tutorial/redirector.rb +52 -0
- data/data/arrow/applets/tutorial/rndimages.rb +159 -0
- data/data/arrow/applets/tutorial/sharenotes.rb +83 -0
- data/data/arrow/applets/tutorial/subclassed-hello.rb +32 -0
- data/data/arrow/applets/tutorial/superhello.rb +72 -0
- data/data/arrow/applets/tutorial/timeclock.rb +78 -0
- data/data/arrow/applets/view-applet.rb +123 -0
- data/data/arrow/applets/view-template.rb +85 -0
- data/data/arrow/applets/wiki.rb +274 -0
- data/data/arrow/templates/TEMPLATE.tmpl.tpl +36 -0
- data/data/arrow/templates/applet-status.tmpl +153 -0
- data/data/arrow/templates/args-display.tmpl +120 -0
- data/data/arrow/templates/config/display-table.tmpl +36 -0
- data/data/arrow/templates/config/display.tmpl +36 -0
- data/data/arrow/templates/counter-deleted.tmpl +33 -0
- data/data/arrow/templates/counter.tmpl +59 -0
- data/data/arrow/templates/dingus.tmpl +55 -0
- data/data/arrow/templates/enumtable.tmpl +8 -0
- data/data/arrow/templates/error-display.tmpl +92 -0
- data/data/arrow/templates/filemap.tmpl +89 -0
- data/data/arrow/templates/hello-world-src.tmpl +34 -0
- data/data/arrow/templates/hello-world.tmpl +60 -0
- data/data/arrow/templates/imgtext/fontlist.tmpl +46 -0
- data/data/arrow/templates/imgtext/form.tmpl +70 -0
- data/data/arrow/templates/imgtext/reload-error.tmpl +40 -0
- data/data/arrow/templates/imgtext/reload.tmpl +55 -0
- data/data/arrow/templates/inspect/display.tmpl +80 -0
- data/data/arrow/templates/loginform.tmpl +64 -0
- data/data/arrow/templates/logout.tmpl +32 -0
- data/data/arrow/templates/memcache/display.tmpl +41 -0
- data/data/arrow/templates/navbar.incl +27 -0
- data/data/arrow/templates/nosuchapplet.tmpl +32 -0
- data/data/arrow/templates/printsource.tmpl +35 -0
- data/data/arrow/templates/protected.tmpl +36 -0
- data/data/arrow/templates/rndimages.tmpl +38 -0
- data/data/arrow/templates/service-response.tmpl +13 -0
- data/data/arrow/templates/sharenotes/display.tmpl +38 -0
- data/data/arrow/templates/status.tmpl +120 -0
- data/data/arrow/templates/templateviewer.tmpl +43 -0
- data/data/arrow/templates/test/harness.tmpl +57 -0
- data/data/arrow/templates/test/list.tmpl +48 -0
- data/data/arrow/templates/test/problem.tmpl +42 -0
- data/data/arrow/templates/tutorial/index.tmpl +37 -0
- data/data/arrow/templates/tutorial/missingapplet.tmpl +29 -0
- data/data/arrow/templates/view-applet-nosuch.tmpl +32 -0
- data/data/arrow/templates/view-applet.tmpl +40 -0
- data/data/arrow/templates/view-template.tmpl +83 -0
- data/data/arrow/templates/wiki/formerror.tmpl +47 -0
- data/data/arrow/templates/wiki/markup_help.incl +6 -0
- data/data/arrow/templates/wiki/new.tmpl +56 -0
- data/data/arrow/templates/wiki/new_system.tmpl +122 -0
- data/data/arrow/templates/wiki/sectionlist.tmpl +43 -0
- data/data/arrow/templates/wiki/show.tmpl +34 -0
- data/docs/manual/layouts/default.page +43 -0
- data/docs/manual/lib/api-filter.rb +81 -0
- data/docs/manual/lib/editorial-filter.rb +64 -0
- data/docs/manual/lib/examples-filter.rb +244 -0
- data/docs/manual/lib/links-filter.rb +117 -0
- data/lib/apache/fakerequest.rb +448 -0
- data/lib/apache/logger.rb +33 -0
- data/lib/arrow.rb +51 -0
- data/lib/arrow/acceptparam.rb +207 -0
- data/lib/arrow/applet.rb +725 -0
- data/lib/arrow/appletmixins.rb +218 -0
- data/lib/arrow/appletregistry.rb +590 -0
- data/lib/arrow/applettestcase.rb +503 -0
- data/lib/arrow/broker.rb +255 -0
- data/lib/arrow/cache.rb +176 -0
- data/lib/arrow/config-loaders/yaml.rb +75 -0
- data/lib/arrow/config.rb +615 -0
- data/lib/arrow/constants.rb +24 -0
- data/lib/arrow/cookie.rb +359 -0
- data/lib/arrow/cookieset.rb +108 -0
- data/lib/arrow/dispatcher.rb +368 -0
- data/lib/arrow/dispatcherloader.rb +50 -0
- data/lib/arrow/exceptions.rb +61 -0
- data/lib/arrow/fallbackhandler.rb +48 -0
- data/lib/arrow/formvalidator.rb +631 -0
- data/lib/arrow/htmltokenizer.rb +343 -0
- data/lib/arrow/logger.rb +488 -0
- data/lib/arrow/logger/apacheoutputter.rb +69 -0
- data/lib/arrow/logger/arrayoutputter.rb +63 -0
- data/lib/arrow/logger/coloroutputter.rb +111 -0
- data/lib/arrow/logger/fileoutputter.rb +96 -0
- data/lib/arrow/logger/htmloutputter.rb +54 -0
- data/lib/arrow/logger/outputter.rb +123 -0
- data/lib/arrow/mixins.rb +425 -0
- data/lib/arrow/monkeypatches.rb +94 -0
- data/lib/arrow/object.rb +117 -0
- data/lib/arrow/path.rb +196 -0
- data/lib/arrow/service.rb +447 -0
- data/lib/arrow/session.rb +289 -0
- data/lib/arrow/session/dbstore.rb +100 -0
- data/lib/arrow/session/filelock.rb +160 -0
- data/lib/arrow/session/filestore.rb +132 -0
- data/lib/arrow/session/id.rb +98 -0
- data/lib/arrow/session/lock.rb +253 -0
- data/lib/arrow/session/md5id.rb +42 -0
- data/lib/arrow/session/nulllock.rb +42 -0
- data/lib/arrow/session/posixlock.rb +166 -0
- data/lib/arrow/session/sha1id.rb +54 -0
- data/lib/arrow/session/store.rb +366 -0
- data/lib/arrow/session/usertrackid.rb +52 -0
- data/lib/arrow/spechelpers.rb +73 -0
- data/lib/arrow/template.rb +713 -0
- data/lib/arrow/template/attr.rb +31 -0
- data/lib/arrow/template/call.rb +31 -0
- data/lib/arrow/template/comment.rb +33 -0
- data/lib/arrow/template/container.rb +118 -0
- data/lib/arrow/template/else.rb +41 -0
- data/lib/arrow/template/elsif.rb +44 -0
- data/lib/arrow/template/escape.rb +53 -0
- data/lib/arrow/template/export.rb +87 -0
- data/lib/arrow/template/for.rb +145 -0
- data/lib/arrow/template/if.rb +78 -0
- data/lib/arrow/template/import.rb +119 -0
- data/lib/arrow/template/include.rb +206 -0
- data/lib/arrow/template/iterator.rb +208 -0
- data/lib/arrow/template/nodes.rb +734 -0
- data/lib/arrow/template/parser.rb +571 -0
- data/lib/arrow/template/prettyprint.rb +53 -0
- data/lib/arrow/template/render.rb +191 -0
- data/lib/arrow/template/selectlist.rb +94 -0
- data/lib/arrow/template/set.rb +87 -0
- data/lib/arrow/template/timedelta.rb +81 -0
- data/lib/arrow/template/unless.rb +78 -0
- data/lib/arrow/template/urlencode.rb +51 -0
- data/lib/arrow/template/yield.rb +139 -0
- data/lib/arrow/templatefactory.rb +125 -0
- data/lib/arrow/testcase.rb +567 -0
- data/lib/arrow/transaction.rb +608 -0
- data/rake/191_compat.rb +26 -0
- data/rake/dependencies.rb +76 -0
- data/rake/documentation.rb +114 -0
- data/rake/helpers.rb +502 -0
- data/rake/hg.rb +282 -0
- data/rake/manual.rb +787 -0
- data/rake/packaging.rb +129 -0
- data/rake/publishing.rb +278 -0
- data/rake/style.rb +62 -0
- data/rake/svn.rb +668 -0
- data/rake/testing.rb +187 -0
- data/rake/verifytask.rb +64 -0
- data/spec/arrow/acceptparam_spec.rb +157 -0
- data/spec/arrow/applet_spec.rb +575 -0
- data/spec/arrow/appletmixins_spec.rb +409 -0
- data/spec/arrow/appletregistry_spec.rb +294 -0
- data/spec/arrow/broker_spec.rb +153 -0
- data/spec/arrow/config_spec.rb +224 -0
- data/spec/arrow/cookieset_spec.rb +164 -0
- data/spec/arrow/dispatcher_spec.rb +137 -0
- data/spec/arrow/dispatcherloader_spec.rb +65 -0
- data/spec/arrow/formvalidator_spec.rb +781 -0
- data/spec/arrow/logger_spec.rb +346 -0
- data/spec/arrow/mixins_spec.rb +120 -0
- data/spec/arrow/service_spec.rb +645 -0
- data/spec/arrow/session_spec.rb +121 -0
- data/spec/arrow/template/iterator_spec.rb +222 -0
- data/spec/arrow/templatefactory_spec.rb +185 -0
- data/spec/arrow/transaction_spec.rb +319 -0
- data/spec/arrow_spec.rb +37 -0
- data/spec/lib/appletmatchers.rb +281 -0
- data/spec/lib/constants.rb +77 -0
- data/spec/lib/helpers.rb +41 -0
- data/spec/lib/matchers.rb +44 -0
- data/tests/cookie.tests.rb +310 -0
- data/tests/path.tests.rb +157 -0
- data/tests/session.tests.rb +111 -0
- data/tests/session_id.tests.rb +82 -0
- data/tests/session_lock.tests.rb +191 -0
- data/tests/session_store.tests.rb +53 -0
- data/tests/template.tests.rb +1360 -0
- metadata +339 -0
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
|
|
3
|
+
require 'arrow/exceptions'
|
|
4
|
+
require 'arrow/session/store'
|
|
5
|
+
|
|
6
|
+
# The Arrow::Session::FileStore class, a derivative of Arrow::Session::Store.
|
|
7
|
+
# Instances of this class store a session object as a marshalled hash on disk.
|
|
8
|
+
#
|
|
9
|
+
# == Authors
|
|
10
|
+
#
|
|
11
|
+
# * Michael Granger <ged@FaerieMUD.org>
|
|
12
|
+
#
|
|
13
|
+
# Please see the file LICENSE in the top-level directory for licensing details.
|
|
14
|
+
#
|
|
15
|
+
class Arrow::Session::FileStore < Arrow::Session::Store
|
|
16
|
+
|
|
17
|
+
# The default flags to use when opening the backing store file
|
|
18
|
+
DefaultIoFlags = File::RDWR|File::CREAT
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
#################################################################
|
|
23
|
+
### I N S T A N C E M E T H O D S
|
|
24
|
+
#################################################################
|
|
25
|
+
|
|
26
|
+
### Create a new Arrow::Session::FileStore object.
|
|
27
|
+
def initialize( uri, idobj )
|
|
28
|
+
path = (uri.path || uri.opaque).dup
|
|
29
|
+
path.untaint
|
|
30
|
+
|
|
31
|
+
@dir = File.expand_path( path )
|
|
32
|
+
@io = nil
|
|
33
|
+
|
|
34
|
+
super
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
######
|
|
39
|
+
public
|
|
40
|
+
######
|
|
41
|
+
|
|
42
|
+
# The fully-qualified directory in which session files will be written.
|
|
43
|
+
attr_reader :dir
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
### Return the fully-qualified path to the session file for this
|
|
47
|
+
### store.
|
|
48
|
+
def session_file
|
|
49
|
+
return File.join( @dir, @id.to_s )
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
### Close the file after saving to make sure it's synched.
|
|
54
|
+
def save
|
|
55
|
+
super
|
|
56
|
+
@io = nil
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
### Get the output filehandle for the session backing store
|
|
61
|
+
### file. Open it with the specified +ioflags+ if it's not
|
|
62
|
+
### already open.
|
|
63
|
+
def open( ioflags=DefaultIoFlags )
|
|
64
|
+
if @io.nil? || @io.closed?
|
|
65
|
+
file = self.session_file
|
|
66
|
+
self.log.debug "Opening session file %s" % file
|
|
67
|
+
@io = File.open( file, File::RDWR|File::CREAT )
|
|
68
|
+
@io.sync = true
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
return @io
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
### Close the output filehandle if it is opened.
|
|
76
|
+
def close
|
|
77
|
+
@io.close unless @io.nil? || @io.closed?
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
### Insert the specified +data+ hash into whatever permanent storage the
|
|
82
|
+
### Store object is acting as an interface to.
|
|
83
|
+
def insert
|
|
84
|
+
super {|data|
|
|
85
|
+
self.log.debug "Inserting data into session file"
|
|
86
|
+
self.open( DefaultIoFlags|File::EXCL ).print( data )
|
|
87
|
+
}
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
### Update the current data hash stored in permanent storage with the
|
|
92
|
+
### values contained in +data+.
|
|
93
|
+
def update
|
|
94
|
+
super {|data|
|
|
95
|
+
self.log.debug "Updating data in session file"
|
|
96
|
+
ofh = self.open
|
|
97
|
+
ofh.seek( 0, File::SEEK_SET )
|
|
98
|
+
ofh.print( data )
|
|
99
|
+
}
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
### Retrieve the data hash stored in permanent storage associated with
|
|
104
|
+
### the id the object was created with.
|
|
105
|
+
def retrieve
|
|
106
|
+
super {
|
|
107
|
+
self.log.debug "Reading data in session file"
|
|
108
|
+
ofh = self.open( File::RDWR )
|
|
109
|
+
ofh.seek( 0, File::SEEK_SET )
|
|
110
|
+
ofh.read
|
|
111
|
+
}
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
### Permanently remove the data hash associated with the id used in the
|
|
116
|
+
### receiver's creation from permanent storage.
|
|
117
|
+
def remove
|
|
118
|
+
super
|
|
119
|
+
self.close
|
|
120
|
+
file = self.session_file
|
|
121
|
+
if File.exists?( file )
|
|
122
|
+
File.delete( file )
|
|
123
|
+
else
|
|
124
|
+
raise Arrow::SessionError,
|
|
125
|
+
"Session file #{file} does not exist in the data store"
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
end # class Arrow::Session::FileStore
|
|
131
|
+
|
|
132
|
+
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
|
|
3
|
+
require 'pluginfactory'
|
|
4
|
+
|
|
5
|
+
require 'arrow/object'
|
|
6
|
+
require 'arrow/mixins'
|
|
7
|
+
require 'arrow/session'
|
|
8
|
+
|
|
9
|
+
# The Arrow::Session::Id class, a derivative of Arrow::Object. Instances of
|
|
10
|
+
# concrete derivatives of this class are used as session IDs in Arrow::Session
|
|
11
|
+
# objects.
|
|
12
|
+
#
|
|
13
|
+
# == Authors
|
|
14
|
+
#
|
|
15
|
+
# * Michael Granger <ged@FaerieMUD.org>
|
|
16
|
+
#
|
|
17
|
+
# Please see the file LICENSE in the top-level directory for licensing details.
|
|
18
|
+
#
|
|
19
|
+
class Arrow::Session::Id < Arrow::Object
|
|
20
|
+
include PluginFactory
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
#############################################################
|
|
24
|
+
### C L A S S M E T H O D S
|
|
25
|
+
#############################################################
|
|
26
|
+
|
|
27
|
+
### Returns the Array of directories to search for derivatives; part of
|
|
28
|
+
### the PluginFactory interface.
|
|
29
|
+
def self::derivativeDirs
|
|
30
|
+
[ 'arrow/session', 'arrow/session/id' ]
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
### Create a new Arrow::Session::Id object for the given +request+ (an
|
|
35
|
+
### Apache::Request) of the type specified by +uri+.
|
|
36
|
+
def self::create( uri, request, idstring=nil )
|
|
37
|
+
uri = Arrow::Session.parse_uri( uri ) if uri.is_a?( String )
|
|
38
|
+
super( uri.scheme.dup, uri, request, idstring )
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
### Generate a new id string for the given +request+.
|
|
43
|
+
def self::generate( uri, request )
|
|
44
|
+
raise NotImplementedError, "%s does not implement #generate" %
|
|
45
|
+
self.name
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
### Validate the given +idstring+, returning an untainted copy of it if
|
|
50
|
+
### it's valid, or +nil+ if it's not.
|
|
51
|
+
def self::validate( uri, idstring )
|
|
52
|
+
raise NotImplementedError, "%s does not implement #validate" %
|
|
53
|
+
self.name
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
#############################################################
|
|
59
|
+
### I N S T A N C E M E T H O D S
|
|
60
|
+
#############################################################
|
|
61
|
+
|
|
62
|
+
### Create a new Arrow::Session::Id object. If the +idstring+ is given, it
|
|
63
|
+
### will be used as the unique key for this session. If it is not
|
|
64
|
+
### specified, a new one will be generated.
|
|
65
|
+
def initialize( uri, request, idstring=nil )
|
|
66
|
+
@new = true
|
|
67
|
+
|
|
68
|
+
if idstring
|
|
69
|
+
self.log.debug "Validating id %p" % [ idstring ]
|
|
70
|
+
@str = self.class.validate( uri, idstring )
|
|
71
|
+
self.log.debug " validation %s" % [ @str ? "succeeded" : "failed" ]
|
|
72
|
+
@new = false
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
@str ||= self.class.generate( uri, request )
|
|
76
|
+
super()
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
######
|
|
81
|
+
public
|
|
82
|
+
######
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
### Return the id as a String.
|
|
86
|
+
def to_s
|
|
87
|
+
return @str
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
### Returns +true+ if the id was generated for this request as opposed
|
|
92
|
+
### to being fetched from a cookie or the URL.
|
|
93
|
+
def new?
|
|
94
|
+
@new ? true : false
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
end # class Arrow::Session::Id
|
|
98
|
+
|
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
|
|
3
|
+
require 'uri'
|
|
4
|
+
require 'pluginfactory'
|
|
5
|
+
|
|
6
|
+
require 'arrow/object'
|
|
7
|
+
require 'arrow/exceptions'
|
|
8
|
+
require 'arrow/mixins'
|
|
9
|
+
require 'arrow/session'
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
# The Arrow::Session::Lock class, which is the abstract
|
|
13
|
+
# superclass for session lock object classes. Locks are objects which fulfill
|
|
14
|
+
# the locking interface of Arrow::Session, providing a way of serializing
|
|
15
|
+
# access to session data.
|
|
16
|
+
#
|
|
17
|
+
# To derive your own lock manager classes from this class, you'll need to
|
|
18
|
+
# follow the following interface:
|
|
19
|
+
#
|
|
20
|
+
# === Derivative Interface ===
|
|
21
|
+
#
|
|
22
|
+
# Locking is achieved via four methods: #acquire_read_lock, #acquire_write_lock,
|
|
23
|
+
# #release_read_lock, and #release_write_lock. These methods provide the
|
|
24
|
+
# #concurrency for sessions shared between multiple servers. You will probably
|
|
25
|
+
# #also want to provide your own initializer to capture the session's ID.
|
|
26
|
+
#
|
|
27
|
+
# #initialize( uri=string, id=Arrow::Session::Id )
|
|
28
|
+
#
|
|
29
|
+
# #acquire_read_lock::
|
|
30
|
+
# Acquire a shared lock on the session data.
|
|
31
|
+
#
|
|
32
|
+
# #acquire_write_lock::
|
|
33
|
+
# Acquire an exclusive lock on the session data.
|
|
34
|
+
#
|
|
35
|
+
# #release_read_lock
|
|
36
|
+
# Release a shared lock on the session data.
|
|
37
|
+
#
|
|
38
|
+
# #release_write_lock::
|
|
39
|
+
# Release an exclusive lock on the session data.
|
|
40
|
+
#
|
|
41
|
+
# == Authors
|
|
42
|
+
#
|
|
43
|
+
# * Michael Granger <ged@FaerieMUD.org>
|
|
44
|
+
#
|
|
45
|
+
# Please see the file LICENSE in the top-level directory for licensing details.
|
|
46
|
+
#
|
|
47
|
+
class Arrow::Session::Lock < Arrow::Object
|
|
48
|
+
include PluginFactory
|
|
49
|
+
|
|
50
|
+
# Lock status flags
|
|
51
|
+
UNLOCKED = 0b00
|
|
52
|
+
READ = 0b01
|
|
53
|
+
WRITE = 0b10
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
#############################################################
|
|
57
|
+
### C L A S S M E T H O D S
|
|
58
|
+
#############################################################
|
|
59
|
+
|
|
60
|
+
### Returns the Array of directories to search for derivatives; part of
|
|
61
|
+
### the PluginFactory interface.
|
|
62
|
+
def self::derivativeDirs
|
|
63
|
+
[ 'arrow/session', 'arrow/session/lock' ]
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
### Create a new Arrow::Session::Lock object for the given +id+ of the
|
|
68
|
+
### type specified by +uri+.
|
|
69
|
+
def self::create( uri, id )
|
|
70
|
+
uri = Arrow::Session.parse_uri( uri ) if
|
|
71
|
+
uri.is_a?( String )
|
|
72
|
+
super( uri.scheme.dup, uri, id )
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
#############################################################
|
|
78
|
+
### I N S T A N C E M E T H O D S
|
|
79
|
+
#############################################################
|
|
80
|
+
|
|
81
|
+
### Create a new Arrow::Session::Lock object.
|
|
82
|
+
def initialize( uri, id )
|
|
83
|
+
super()
|
|
84
|
+
@status = UNLOCKED
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
######
|
|
89
|
+
public
|
|
90
|
+
######
|
|
91
|
+
|
|
92
|
+
### Acquire a read (shared) lock. If +blocking+ is false, will return
|
|
93
|
+
### +false+ if the lock was not able to be acquired.
|
|
94
|
+
def read_lock( blocking=true )
|
|
95
|
+
return true if self.read_locked?
|
|
96
|
+
self.log.debug "Acquiring read lock"
|
|
97
|
+
self.acquire_read_lock( blocking ) or return false
|
|
98
|
+
@status |= READ
|
|
99
|
+
self.log.debug "Got read lock"
|
|
100
|
+
return true
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
### Acquire a write (exclusive) lock. If +blocking+ is false, will
|
|
105
|
+
### return +false+ if the lock was not able to be acquired.
|
|
106
|
+
def write_lock( blocking=true )
|
|
107
|
+
return true if self.write_locked?
|
|
108
|
+
self.log.debug "Acquiring write lock"
|
|
109
|
+
self.acquire_write_lock( blocking ) or return false
|
|
110
|
+
@status |= WRITE
|
|
111
|
+
self.log.debug "Got write lock"
|
|
112
|
+
return true
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
### Execute the given block after obtaining a read lock, and give up the
|
|
117
|
+
### lock when the block returns. If +blocking+ is false, will raise an
|
|
118
|
+
### Errno::EAGAIN error without calling the block if the lock cannot be
|
|
119
|
+
### immediately established.
|
|
120
|
+
def with_read_lock( blocking=true )
|
|
121
|
+
begin
|
|
122
|
+
self.read_lock( blocking ) or raise Errno::EAGAIN
|
|
123
|
+
yield
|
|
124
|
+
ensure
|
|
125
|
+
self.release_read_lock
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
### Execute the given block after obtaining a write lock, and give up
|
|
131
|
+
### the lock when the block returns. If +blocking+ is false, will raise
|
|
132
|
+
### an Errno::EAGAIN error without calling the block if the lock cannot
|
|
133
|
+
### be immediately established.
|
|
134
|
+
def with_write_lock( blocking=true )
|
|
135
|
+
begin
|
|
136
|
+
self.write_lock( blocking ) or raise Errno::EAGAIN
|
|
137
|
+
yield
|
|
138
|
+
ensure
|
|
139
|
+
self.release_write_lock
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
### Returns +true+ if the lock object currently holds either a read or
|
|
145
|
+
### write lock.
|
|
146
|
+
def locked?
|
|
147
|
+
(@status & (READ|WRITE)).nonzero?
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
### Returns +true+ if the lock object has acquired a read lock.
|
|
152
|
+
def read_locked?
|
|
153
|
+
(@status & READ).nonzero?
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
### Returns +true+ if the lock object has acquired a write lock.
|
|
158
|
+
def write_locked?
|
|
159
|
+
(@status & WRITE).nonzero?
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
### Give up a read (shared) lock. Raises an exception if no read lock
|
|
164
|
+
### has been acquired.
|
|
165
|
+
def read_unlock
|
|
166
|
+
raise Arrow::LockingError, "No read lock to release" unless
|
|
167
|
+
self.read_locked?
|
|
168
|
+
self.log.debug "Releasing read lock"
|
|
169
|
+
self.release_read_lock
|
|
170
|
+
@status &= ( @status ^ READ )
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
### Release a write (exclusive) lock. Raises an exception if no write
|
|
175
|
+
### lock has been acquired.
|
|
176
|
+
def write_unlock
|
|
177
|
+
raise Arrow::LockingError, "No write lock to release" unless
|
|
178
|
+
self.write_locked?
|
|
179
|
+
self.log.debug "Releasing write lock"
|
|
180
|
+
self.release_write_lock
|
|
181
|
+
@status &= ( @status ^ WRITE )
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
### Release any locks acquired by this lock object.
|
|
186
|
+
def release_all_locks
|
|
187
|
+
return false unless self.locked?
|
|
188
|
+
self.write_unlock if self.write_locked?
|
|
189
|
+
self.read_unlock if self.read_locked?
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
### Indicate to the lock that the caller will no longer be using it, and
|
|
194
|
+
### it may free any resources it had been using.
|
|
195
|
+
def finish
|
|
196
|
+
self.release_all_locks
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
#########
|
|
201
|
+
protected
|
|
202
|
+
#########
|
|
203
|
+
|
|
204
|
+
### Interface method for concrete derivatives: acquire a read lock
|
|
205
|
+
### through whatever mechanism is being implemented. If +blocking+ is
|
|
206
|
+
### +true+, the method should only return if the lock was successfully
|
|
207
|
+
### acquired. If +blocking+ is +false+, this method should attempt the
|
|
208
|
+
### lock and return +false+ immediately if the lock was not able to the
|
|
209
|
+
### acquired. Concrete implementations should *not* call +super+ for
|
|
210
|
+
### this method.
|
|
211
|
+
def acquire_read_lock( blocking )
|
|
212
|
+
raise UnimplementedError,
|
|
213
|
+
"%s does not provide an implementation of #acquire_read_lock." %
|
|
214
|
+
self.class.name
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
### Interface method for concrete derivatives: acquire a write lock
|
|
219
|
+
### through whatever mechanism is being implemented. If +blocking+ is
|
|
220
|
+
### +true+, the method should only return if the lock was successfully
|
|
221
|
+
### acquired. If +blocking+ is +false+, this method should attempt the
|
|
222
|
+
### lock and return +false+ immediately if the lock was not able to the
|
|
223
|
+
### acquired. Concrete implementations should *not* call +super+ for
|
|
224
|
+
### this method.
|
|
225
|
+
def acquire_write_lock( blocking )
|
|
226
|
+
raise UnimplementedError,
|
|
227
|
+
"%s does not provide an implementation of #acquire_write_lock." %
|
|
228
|
+
self.class.name
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
### Interface method for concrete derivatives: release a read lock
|
|
233
|
+
### through whatever mechanism is being implemented. Concrete
|
|
234
|
+
### implementations should *not* call +super+ for this method.
|
|
235
|
+
def release_read_lock
|
|
236
|
+
raise UnimplementedError,
|
|
237
|
+
"%s does not provide an implementation of #release_read_lock." %
|
|
238
|
+
self.class.name
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
### Interface method for concrete derivatives: release a write lock
|
|
243
|
+
### through whatever mechanism is being implemented. Concrete
|
|
244
|
+
### implementations should *not* call +super+ for this method.
|
|
245
|
+
def release_write_lock
|
|
246
|
+
raise UnimplementedError,
|
|
247
|
+
"%s does not provide an implementation of #release_write_lock." %
|
|
248
|
+
self.class.name
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
end # class Arrow::Session::Lock
|
|
252
|
+
|
|
253
|
+
|