lore 0.4.2
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +19 -0
- data/README +74 -0
- data/aspect.rb +80 -0
- data/behaviours/lockable.rb +41 -0
- data/behaviours/movable.rb +54 -0
- data/behaviours/versioned.rb +24 -0
- data/benchmark.rb +193 -0
- data/bits.rb +52 -0
- data/cache/abstract_entity_cache.rb +82 -0
- data/cache/bits.rb +22 -0
- data/cache/cacheable.rb +202 -0
- data/cache/cached_entities.rb +116 -0
- data/cache/file_index.rb +35 -0
- data/cache/mmap_entity_cache.rb +67 -0
- data/clause.rb +528 -0
- data/connection.rb +155 -0
- data/custom_functions.sql +14 -0
- data/exception/ambiguous_attribute.rb +14 -0
- data/exception/cache_exception.rb +30 -0
- data/exception/invalid_klass_parameters.rb +63 -0
- data/exception/invalid_parameter.rb +42 -0
- data/exception/unknown_typecode.rb +19 -0
- data/file_index.sql +56 -0
- data/gui/erb_template.rb +79 -0
- data/gui/erb_template_helpers.rhtml +19 -0
- data/gui/form.rb +314 -0
- data/gui/form_element.rb +676 -0
- data/gui/form_generator.rb +151 -0
- data/gui/templates/button.rhtml +2 -0
- data/gui/templates/checkbox.rhtml +3 -0
- data/gui/templates/checkbox_row.rhtml +1 -0
- data/gui/templates/file.rhtml +2 -0
- data/gui/templates/file_readonly.rhtml +3 -0
- data/gui/templates/form_element.rhtml +5 -0
- data/gui/templates/form_element_horizontal.rhtml +3 -0
- data/gui/templates/form_element_listed.rhtml +8 -0
- data/gui/templates/form_table.rhtml +3 -0
- data/gui/templates/form_table_blank.rhtml +3 -0
- data/gui/templates/form_table_horizontal.rhtml +8 -0
- data/gui/templates/password.rhtml +2 -0
- data/gui/templates/password_readonly.rhtml +3 -0
- data/gui/templates/radio.rhtml +1 -0
- data/gui/templates/radio_row.rhtml +1 -0
- data/gui/templates/select.rhtml +23 -0
- data/gui/templates/text.rhtml +2 -0
- data/gui/templates/text_readonly.rhtml +3 -0
- data/gui/templates/textarea.rhtml +3 -0
- data/gui/templates/textarea_readonly.rhtml +4 -0
- data/lore.gemspec +40 -0
- data/lore.rb +94 -0
- data/migration.rb +48 -0
- data/model.rb +139 -0
- data/model_factory.rb +202 -0
- data/model_shortcuts.rb +16 -0
- data/query_shortcuts.rb +367 -0
- data/reserved_methods.txt +3 -0
- data/result.rb +100 -0
- data/symbol.rb +58 -0
- data/table_accessor.rb +1926 -0
- data/table_deleter.rb +115 -0
- data/table_inserter.rb +168 -0
- data/table_instance.rb +384 -0
- data/table_selector.rb +314 -0
- data/table_updater.rb +155 -0
- data/test/README +31 -0
- data/test/env.rb +5 -0
- data/test/lore_test.log +8218 -0
- data/test/model.rb +142 -0
- data/test/prepare.rb +37 -0
- data/test/tc_aspect.rb +58 -0
- data/test/tc_cache.rb +80 -0
- data/test/tc_clause.rb +104 -0
- data/test/tc_deep_inheritance.rb +49 -0
- data/test/tc_factory.rb +57 -0
- data/test/tc_filter.rb +37 -0
- data/test/tc_form.rb +32 -0
- data/test/tc_model.rb +86 -0
- data/test/tc_prepare.rb +45 -0
- data/test/tc_refined_query.rb +88 -0
- data/test/tc_table_accessor.rb +265 -0
- data/test/test.log +181 -0
- data/test/test_db.sql +400 -0
- data/test/ts_lore.rb +49 -0
- data/types.rb +55 -0
- data/validation/message.rb +60 -0
- data/validation/parameter_validator.rb +104 -0
- data/validation/reason.rb +54 -0
- data/validation/type_validator.rb +91 -0
- data/validation.rb +65 -0
- metadata +170 -0
data/cache/cacheable.rb
ADDED
@@ -0,0 +1,202 @@
|
|
1
|
+
|
2
|
+
require('pstore')
|
3
|
+
|
4
|
+
require('lore/cache/bits')
|
5
|
+
require('lore/exception/cache_exception')
|
6
|
+
|
7
|
+
module Lore
|
8
|
+
module Cache
|
9
|
+
|
10
|
+
module Cacheable
|
11
|
+
|
12
|
+
@@cache_control = Hash.new
|
13
|
+
@@cache_on_pkeys = Hash.new
|
14
|
+
@@distinctive_params = Hash.new
|
15
|
+
@@cache_entities = false
|
16
|
+
|
17
|
+
@@logger = Lore.logger
|
18
|
+
|
19
|
+
public
|
20
|
+
|
21
|
+
def is_cacheable(controller)
|
22
|
+
controller = controller.intern unless controller.instance_of? Symbol
|
23
|
+
return !@@cache_control[controller].nil? && @@cache_control[controller]
|
24
|
+
end
|
25
|
+
|
26
|
+
# Returns whether a Table_Accessor state
|
27
|
+
# is cached or not.
|
28
|
+
def is_cached(controller, mode, keys)
|
29
|
+
|
30
|
+
store_filename = Lore::Cache::store_name(self.name.to_s, controller, mode, keys)
|
31
|
+
if store_filename.nil? then
|
32
|
+
excep_mesg = 'Cannot resolve store filename for ['+self.name.to_s+'|'+controller+'|'+mode+']'
|
33
|
+
excep_mesg += ' Keys: '+keys.to_s
|
34
|
+
raise ::Exception.new(excep_mesg)
|
35
|
+
end
|
36
|
+
|
37
|
+
if FileTest.exist?(store_filename) then
|
38
|
+
true
|
39
|
+
else
|
40
|
+
false
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
protected
|
46
|
+
|
47
|
+
def cache(controller, additional_params=nil)
|
48
|
+
controller = controller.intern unless controller.instance_of? Symbol
|
49
|
+
@@cache_control[controller] = true
|
50
|
+
if !additional_params.nil? then
|
51
|
+
@@distinctive_params[controller] = Array.new unless !@@distinctive_params[controller].nil?
|
52
|
+
@@distinctive_params[controller] += additional_params
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
def cache_select_entities
|
58
|
+
@@cache_entities = true
|
59
|
+
end
|
60
|
+
|
61
|
+
def cache_entities
|
62
|
+
@@cache_entities
|
63
|
+
end
|
64
|
+
|
65
|
+
def cache_on_pkeys(controller, additional_params=nil)
|
66
|
+
@@logger.log('Caching depending from pkeys only, controller: ' << controller.to_s << ', params: ' << additional_params.to_s)
|
67
|
+
cache(controller, additional_params)
|
68
|
+
@@cache_on_pkeys[controller] = true
|
69
|
+
end
|
70
|
+
|
71
|
+
def cache_pkeys_only?(controller)
|
72
|
+
!@@cache_on_pkeys[controller].nil? && @@cache_on_pkeys[controller]
|
73
|
+
end
|
74
|
+
|
75
|
+
def nocache(controller)
|
76
|
+
controller = controller.intern unless controller.instance_of? Symbol
|
77
|
+
@@cache_control[controller] = false
|
78
|
+
end
|
79
|
+
|
80
|
+
public
|
81
|
+
|
82
|
+
def cache_params(controller)
|
83
|
+
return @@distinctive_params[controller] unless @@distinctive_params[controller].nil?
|
84
|
+
return Hash.new
|
85
|
+
end
|
86
|
+
|
87
|
+
def create_cache(controller, mode, keys, output)
|
88
|
+
|
89
|
+
@@logger.log('cache_on_pkeys: '+@@cache_on_pkeys.inspect)
|
90
|
+
if !@@cache_on_pkeys[controller.intern].nil? &&
|
91
|
+
@@cache_on_pkeys[controller.intern]
|
92
|
+
then
|
93
|
+
keys = filter_pkeys(self, controller, keys)
|
94
|
+
@@logger.log('Filtered keys: '+keys.inspect)
|
95
|
+
end
|
96
|
+
|
97
|
+
if !@@cache_control[controller.intern].nil? &&
|
98
|
+
@@cache_control[controller.intern]
|
99
|
+
then
|
100
|
+
|
101
|
+
if !@@cache_control[:self].nil? &&
|
102
|
+
@@cache_control[:self]
|
103
|
+
then
|
104
|
+
class_copy = self
|
105
|
+
end
|
106
|
+
|
107
|
+
if is_cached(controller, mode, keys) then
|
108
|
+
return
|
109
|
+
end
|
110
|
+
|
111
|
+
store = create_store(controller, mode, keys, output)
|
112
|
+
store.transaction do
|
113
|
+
store['klass'] = class_copy unless class_copy.nil?
|
114
|
+
store['controller'] = controller
|
115
|
+
store['mode'] = mode
|
116
|
+
store['keys'] = keys
|
117
|
+
store['output'] = output
|
118
|
+
end
|
119
|
+
|
120
|
+
else
|
121
|
+
raise Cache_Write_Exception.new(self.name.to_s, controller, mode, keys)
|
122
|
+
end
|
123
|
+
|
124
|
+
end
|
125
|
+
|
126
|
+
public
|
127
|
+
|
128
|
+
def create_cache!(controller, mode, keys, output)
|
129
|
+
invalidate(controller, mode, keys)
|
130
|
+
create_cache(controller, mode, keys)
|
131
|
+
end
|
132
|
+
|
133
|
+
public
|
134
|
+
|
135
|
+
def read_cache(controller, mode, keys)
|
136
|
+
|
137
|
+
if !@@cache_control[controller.intern].nil? &&
|
138
|
+
@@cache_control[controller.intern] &&
|
139
|
+
is_cached(controller, mode, keys)
|
140
|
+
then
|
141
|
+
|
142
|
+
output = ''
|
143
|
+
store = create_store(controller, mode, keys, output)
|
144
|
+
store.transaction do
|
145
|
+
output = store['output']
|
146
|
+
end
|
147
|
+
|
148
|
+
return output
|
149
|
+
|
150
|
+
else
|
151
|
+
raise Cache_Read_Exception.new(self.name.to_s, controller, mode, keys)
|
152
|
+
end
|
153
|
+
|
154
|
+
end
|
155
|
+
|
156
|
+
def invalidate(controller, mode, keys)
|
157
|
+
File.unlink(Lore::Cache::store_name(self.name.to_s, controller, mode, keys))
|
158
|
+
end
|
159
|
+
def invalidate_all(controller=:all, mode=:all, keys=:all)
|
160
|
+
cwd = Dir.getwd
|
161
|
+
Dir.chdir('/tmp/')
|
162
|
+
if keys == :all then keys = Hash.new end
|
163
|
+
invalid_cache_pattern = Lore::Cache::store_name(self.name.to_s, controller, mode, keys)
|
164
|
+
@@logger.log('Deleting cache for: '+invalid_cache_pattern)
|
165
|
+
invalid_cache_files = Dir.glob(invalid_cache_pattern)
|
166
|
+
invalid_cache_files.each { |cache_file|
|
167
|
+
@@logger.log('Deleting '+cache_file)
|
168
|
+
File.delete(cache_file)
|
169
|
+
}
|
170
|
+
Dir.chdir(cwd)
|
171
|
+
end
|
172
|
+
|
173
|
+
private
|
174
|
+
|
175
|
+
def create_store(controller, mode, keys, output)
|
176
|
+
store_file = Lore::Cache::store_name(self.to_s, controller, mode, keys)
|
177
|
+
store = PStore.new(store_file) unless store_file.nil?
|
178
|
+
return store
|
179
|
+
end
|
180
|
+
|
181
|
+
def filter_pkeys(model_klass, controller, keys)
|
182
|
+
if !model_klass.respond_to? 'key_array' then
|
183
|
+
@@logger.log('could not filter for pkeys')
|
184
|
+
return keys
|
185
|
+
end
|
186
|
+
result = Hash.new
|
187
|
+
model_klass.key_array.each { |pkey|
|
188
|
+
result[pkey] = keys[pkey]
|
189
|
+
}
|
190
|
+
if !@@distinctive_params[controller].nil? then
|
191
|
+
@@distinctive_params[controller].each { |param|
|
192
|
+
result[param] = keys[param]
|
193
|
+
}
|
194
|
+
end
|
195
|
+
|
196
|
+
return result
|
197
|
+
end
|
198
|
+
|
199
|
+
end
|
200
|
+
|
201
|
+
end # module
|
202
|
+
end # module
|
@@ -0,0 +1,116 @@
|
|
1
|
+
|
2
|
+
require('logger')
|
3
|
+
|
4
|
+
module Lore
|
5
|
+
module Cache
|
6
|
+
|
7
|
+
class Cached_Entities
|
8
|
+
|
9
|
+
@@logger = Lore.logger
|
10
|
+
@@mmap_cache = Hash.new
|
11
|
+
@@file_index = Hash.new
|
12
|
+
|
13
|
+
public
|
14
|
+
|
15
|
+
def self.flush(type)
|
16
|
+
index = type.table_name
|
17
|
+
return if (!Lore.cache_entities() || @@file_index[index].nil?)
|
18
|
+
@@file_index[index].each { |cache_file|
|
19
|
+
@@logger.debug { 'Clearing cache file ' << cache_file }
|
20
|
+
File.unlink(cache_file)
|
21
|
+
}
|
22
|
+
@@file_index.delete(type.table_name)
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.[]=(query_string, result)
|
26
|
+
if $cb__use_pstore_cache then
|
27
|
+
create_pstore_cache(query_string, result)
|
28
|
+
else
|
29
|
+
create_mmap_cache(query_string, result)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.create(accessor, query_string, result)
|
34
|
+
if $cb__use_pstore_cache then
|
35
|
+
file = create_pstore_cache(query_string, result)
|
36
|
+
else
|
37
|
+
file = create_mmap_cache(query_string, result)
|
38
|
+
end
|
39
|
+
@@file_index[accessor.table_name] = Array.new unless @@file_index[accessor.table_name]
|
40
|
+
@@file_index[accessor.table_name] << file
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.[](query_string)
|
44
|
+
if $cb__use_pstore_cache then
|
45
|
+
return read_pstore_cache(query_string)
|
46
|
+
else
|
47
|
+
return read_mmap_cache(query_string)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def self.include?(query_string)
|
52
|
+
FileTest.exist?(storefile_of(query_string))
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def self.create_pstore_cache(query_string, result)
|
58
|
+
storefile = storefile_of(query_string)
|
59
|
+
store = create_store(storefile)
|
60
|
+
store.transaction do
|
61
|
+
store['dump'] = result
|
62
|
+
end
|
63
|
+
return storefile
|
64
|
+
end
|
65
|
+
|
66
|
+
def self.read_pstore_cache(query_string)
|
67
|
+
store = create_store(storefile_of(query_string))
|
68
|
+
result = Array.new
|
69
|
+
store.transaction do
|
70
|
+
result = store['dump']
|
71
|
+
end
|
72
|
+
return result
|
73
|
+
end
|
74
|
+
|
75
|
+
def self.create_mmap_cache(query_string, result)
|
76
|
+
storefile = storefile_of(query_string)
|
77
|
+
store = create_store(storefile)
|
78
|
+
store.transaction do
|
79
|
+
store['dump'] = result
|
80
|
+
end
|
81
|
+
@@mmap_cache[index_for(query_string)] = Mmap.new(storefile)
|
82
|
+
return storefile
|
83
|
+
end
|
84
|
+
|
85
|
+
def self.read_mmap_cache(query_string)
|
86
|
+
@@logger.debug { 'Loading from cache: ' << index_for(query_string) }
|
87
|
+
store = @@mmap_cache[index_for(query_string)]
|
88
|
+
@@logger.debug { 'STORE: ' << store.inspect }
|
89
|
+
return [] unless store
|
90
|
+
result = Marshal::load(store)
|
91
|
+
return result['dump']
|
92
|
+
end
|
93
|
+
|
94
|
+
def self.delete_mmap_cache(index)
|
95
|
+
@@mmap_cache[index].munmap
|
96
|
+
end
|
97
|
+
|
98
|
+
private
|
99
|
+
|
100
|
+
def self.index_for(query)
|
101
|
+
Digest::MD5.hexdigest(query)
|
102
|
+
end
|
103
|
+
|
104
|
+
def self.storefile_of(query)
|
105
|
+
'/tmp/cb__cache__entities__' << Digest::MD5.hexdigest(query)
|
106
|
+
end
|
107
|
+
|
108
|
+
def self.create_store(storefile_name)
|
109
|
+
store = PStore.new(storefile_name) unless storefile_name.nil?
|
110
|
+
return store
|
111
|
+
end
|
112
|
+
|
113
|
+
end
|
114
|
+
|
115
|
+
end
|
116
|
+
end
|
data/cache/file_index.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
|
2
|
+
require 'lore/model'
|
3
|
+
|
4
|
+
Lore.disable_cache
|
5
|
+
|
6
|
+
module Lore
|
7
|
+
module Cache
|
8
|
+
|
9
|
+
class File_Index < Lore::Model
|
10
|
+
context :lore
|
11
|
+
table :file_index, :public
|
12
|
+
primary_key :file_index_id, :file_index_id_seq
|
13
|
+
|
14
|
+
# Return array of cache file names depending
|
15
|
+
# from model
|
16
|
+
def self.for(table_name)
|
17
|
+
select { |i|
|
18
|
+
i.where(i.model == table_name)
|
19
|
+
}.collect { |index|
|
20
|
+
index.file
|
21
|
+
}
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.delete_entry(table_name)
|
25
|
+
delete { |i|
|
26
|
+
i.where(i.model == table_name)
|
27
|
+
}
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
Lore.enable_cache
|
@@ -0,0 +1,67 @@
|
|
1
|
+
|
2
|
+
require 'lore'
|
3
|
+
require 'lore/cache/abstract_entity_cache'
|
4
|
+
require 'mmap'
|
5
|
+
|
6
|
+
module Lore
|
7
|
+
module Cache
|
8
|
+
|
9
|
+
|
10
|
+
# Implementation of entity cache using MMapped PStor files.
|
11
|
+
# Derived from Abstract_Entity_Cache.
|
12
|
+
# Uses Lore::Cache::Cache_Helpers for generating PStor files.
|
13
|
+
class Mmap_Entity_Cache < Abstract_Entity_Cache
|
14
|
+
extend Cache_Helpers
|
15
|
+
|
16
|
+
@@logger = Logger.new('/tmp/lore_cache.log')
|
17
|
+
|
18
|
+
|
19
|
+
def self.flush(accessor)
|
20
|
+
index = accessor.table_name
|
21
|
+
return unless Lore.cache_enabled?
|
22
|
+
Dir.glob("/tmp/lore_cache__#{index}*").each { |cache_file|
|
23
|
+
@@logger.debug('Clearing cache file ' << cache_file)
|
24
|
+
begin
|
25
|
+
File.unlink(cache_file)
|
26
|
+
rescue ::Exception => excep
|
27
|
+
# Another process already killed this file
|
28
|
+
end
|
29
|
+
}
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.read(accessor, query_string)
|
33
|
+
@@logger.debug('Loading from cache: ' << index_for(query_string))
|
34
|
+
store = Mmap.new(storefile_of(accessor.table_name, query_string))
|
35
|
+
@@logger.debug('STORE: ' << store.inspect)
|
36
|
+
return [] unless store
|
37
|
+
result = Marshal::load(store)
|
38
|
+
return result['dump']
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.create(accessor, query_string, result)
|
42
|
+
storefile = create_mmap(accessor, query_string, result)
|
43
|
+
end
|
44
|
+
def self.create_mmap(accessor, query_string, result)
|
45
|
+
storefile = storefile_of(accessor.table_name, query_string)
|
46
|
+
store = create_store(storefile)
|
47
|
+
store.transaction do
|
48
|
+
store['dump'] = result
|
49
|
+
end
|
50
|
+
@@logger.debug('Creating cache entry for ' << storefile )
|
51
|
+
Mmap.new(storefile)
|
52
|
+
return storefile
|
53
|
+
end
|
54
|
+
|
55
|
+
def self.include?(accessor, query_string)
|
56
|
+
FileTest.exist?(storefile_of(accessor.table_name, query_string))
|
57
|
+
end
|
58
|
+
|
59
|
+
def self.delete(index)
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
|