picky 0.0.0 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (161) hide show
  1. data/bin/picky +14 -0
  2. data/lib/bundling.rb +10 -0
  3. data/lib/constants.rb +9 -0
  4. data/lib/deployment.rb +212 -0
  5. data/lib/picky/application.rb +40 -0
  6. data/lib/picky/cacher/convenience.rb +3 -0
  7. data/lib/picky/cacher/generator.rb +17 -0
  8. data/lib/picky/cacher/partial/default.rb +7 -0
  9. data/lib/picky/cacher/partial/none.rb +19 -0
  10. data/lib/picky/cacher/partial/strategy.rb +7 -0
  11. data/lib/picky/cacher/partial/subtoken.rb +91 -0
  12. data/lib/picky/cacher/partial_generator.rb +15 -0
  13. data/lib/picky/cacher/similarity/default.rb +7 -0
  14. data/lib/picky/cacher/similarity/double_levenshtone.rb +73 -0
  15. data/lib/picky/cacher/similarity/none.rb +25 -0
  16. data/lib/picky/cacher/similarity/strategy.rb +7 -0
  17. data/lib/picky/cacher/similarity_generator.rb +15 -0
  18. data/lib/picky/cacher/weights/default.rb +7 -0
  19. data/lib/picky/cacher/weights/logarithmic.rb +39 -0
  20. data/lib/picky/cacher/weights/strategy.rb +7 -0
  21. data/lib/picky/cacher/weights_generator.rb +15 -0
  22. data/lib/picky/configuration/configuration.rb +13 -0
  23. data/lib/picky/configuration/field.rb +68 -0
  24. data/lib/picky/configuration/indexes.rb +60 -0
  25. data/lib/picky/configuration/queries.rb +32 -0
  26. data/lib/picky/configuration/type.rb +52 -0
  27. data/lib/picky/cores.rb +101 -0
  28. data/lib/picky/db/configuration.rb +23 -0
  29. data/lib/picky/ext/ruby19/extconf.rb +7 -0
  30. data/lib/picky/ext/ruby19/performant.c +339 -0
  31. data/lib/picky/extensions/array.rb +45 -0
  32. data/lib/picky/extensions/hash.rb +11 -0
  33. data/lib/picky/extensions/module.rb +15 -0
  34. data/lib/picky/extensions/symbol.rb +18 -0
  35. data/lib/picky/generator.rb +156 -0
  36. data/lib/picky/helpers/cache.rb +23 -0
  37. data/lib/picky/helpers/gc.rb +11 -0
  38. data/lib/picky/helpers/measuring.rb +45 -0
  39. data/lib/picky/helpers/search.rb +27 -0
  40. data/lib/picky/index/bundle.rb +328 -0
  41. data/lib/picky/index/category.rb +109 -0
  42. data/lib/picky/index/combined.rb +38 -0
  43. data/lib/picky/index/type.rb +30 -0
  44. data/lib/picky/indexers/base.rb +77 -0
  45. data/lib/picky/indexers/default.rb +3 -0
  46. data/lib/picky/indexers/field.rb +13 -0
  47. data/lib/picky/indexers/no_source_specified_error.rb +5 -0
  48. data/lib/picky/indexers/solr.rb +60 -0
  49. data/lib/picky/indexes.rb +180 -0
  50. data/lib/picky/initializers/ext.rb +6 -0
  51. data/lib/picky/initializers/mysql.rb +22 -0
  52. data/lib/picky/loader.rb +287 -0
  53. data/lib/picky/loggers/search.rb +19 -0
  54. data/lib/picky/performant/array.rb +23 -0
  55. data/lib/picky/query/allocation.rb +82 -0
  56. data/lib/picky/query/allocations.rb +131 -0
  57. data/lib/picky/query/base.rb +124 -0
  58. data/lib/picky/query/combination.rb +69 -0
  59. data/lib/picky/query/combinations.rb +106 -0
  60. data/lib/picky/query/combinator.rb +92 -0
  61. data/lib/picky/query/full.rb +15 -0
  62. data/lib/picky/query/live.rb +22 -0
  63. data/lib/picky/query/qualifiers.rb +73 -0
  64. data/lib/picky/query/solr.rb +77 -0
  65. data/lib/picky/query/token.rb +215 -0
  66. data/lib/picky/query/tokens.rb +102 -0
  67. data/lib/picky/query/weigher.rb +159 -0
  68. data/lib/picky/query/weights.rb +55 -0
  69. data/lib/picky/rack/harakiri.rb +37 -0
  70. data/lib/picky/results/base.rb +103 -0
  71. data/lib/picky/results/full.rb +19 -0
  72. data/lib/picky/results/live.rb +19 -0
  73. data/lib/picky/routing.rb +165 -0
  74. data/lib/picky/signals.rb +11 -0
  75. data/lib/picky/solr/schema_generator.rb +73 -0
  76. data/lib/picky/sources/base.rb +19 -0
  77. data/lib/picky/sources/csv.rb +30 -0
  78. data/lib/picky/sources/db.rb +77 -0
  79. data/lib/picky/tokenizers/base.rb +130 -0
  80. data/lib/picky/tokenizers/default.rb +3 -0
  81. data/lib/picky/tokenizers/index.rb +73 -0
  82. data/lib/picky/tokenizers/query.rb +70 -0
  83. data/lib/picky/umlaut_substituter.rb +21 -0
  84. data/lib/picky-tasks.rb +6 -0
  85. data/lib/picky.rb +18 -0
  86. data/lib/tasks/application.rake +5 -0
  87. data/lib/tasks/cache.rake +53 -0
  88. data/lib/tasks/framework.rake +4 -0
  89. data/lib/tasks/index.rake +29 -0
  90. data/lib/tasks/server.rake +48 -0
  91. data/lib/tasks/shortcuts.rake +13 -0
  92. data/lib/tasks/solr.rake +36 -0
  93. data/lib/tasks/spec.rake +11 -0
  94. data/lib/tasks/statistics.rake +13 -0
  95. data/lib/tasks/try.rake +29 -0
  96. data/prototype_project/Gemfile +23 -0
  97. data/prototype_project/Rakefile +1 -0
  98. data/prototype_project/app/README +6 -0
  99. data/prototype_project/app/application.rb +50 -0
  100. data/prototype_project/app/application.ru +29 -0
  101. data/prototype_project/app/db.yml +10 -0
  102. data/prototype_project/app/logging.rb +20 -0
  103. data/prototype_project/app/unicorn.ru +10 -0
  104. data/prototype_project/log/README +1 -0
  105. data/prototype_project/script/console +34 -0
  106. data/prototype_project/tmp/README +0 -0
  107. data/prototype_project/tmp/pids/README +0 -0
  108. data/spec/ext/performant_spec.rb +64 -0
  109. data/spec/lib/application_spec.rb +61 -0
  110. data/spec/lib/cacher/partial/subtoken_spec.rb +89 -0
  111. data/spec/lib/cacher/partial_generator_spec.rb +35 -0
  112. data/spec/lib/cacher/similarity/double_levenshtone_spec.rb +60 -0
  113. data/spec/lib/cacher/similarity/none_spec.rb +23 -0
  114. data/spec/lib/cacher/similarity_generator_spec.rb +22 -0
  115. data/spec/lib/cacher/weights/logarithmic_spec.rb +30 -0
  116. data/spec/lib/cacher/weights_generator_spec.rb +21 -0
  117. data/spec/lib/configuration/configuration_spec.rb +38 -0
  118. data/spec/lib/configuration/type_spec.rb +49 -0
  119. data/spec/lib/configuration_spec.rb +8 -0
  120. data/spec/lib/cores_spec.rb +65 -0
  121. data/spec/lib/extensions/array_spec.rb +37 -0
  122. data/spec/lib/extensions/hash_spec.rb +11 -0
  123. data/spec/lib/extensions/module_spec.rb +27 -0
  124. data/spec/lib/extensions/symbol_spec.rb +85 -0
  125. data/spec/lib/generator_spec.rb +135 -0
  126. data/spec/lib/helpers/cache_spec.rb +35 -0
  127. data/spec/lib/helpers/gc_spec.rb +71 -0
  128. data/spec/lib/helpers/measuring_spec.rb +18 -0
  129. data/spec/lib/helpers/search_spec.rb +50 -0
  130. data/spec/lib/index/bundle_partial_generation_speed_spec.rb +47 -0
  131. data/spec/lib/index/bundle_spec.rb +260 -0
  132. data/spec/lib/index/category_spec.rb +203 -0
  133. data/spec/lib/indexers/base_spec.rb +73 -0
  134. data/spec/lib/indexers/field_spec.rb +20 -0
  135. data/spec/lib/loader_spec.rb +48 -0
  136. data/spec/lib/loggers/search_spec.rb +19 -0
  137. data/spec/lib/performant/array_spec.rb +13 -0
  138. data/spec/lib/query/allocation_spec.rb +194 -0
  139. data/spec/lib/query/allocations_spec.rb +336 -0
  140. data/spec/lib/query/base_spec.rb +104 -0
  141. data/spec/lib/query/combination_spec.rb +90 -0
  142. data/spec/lib/query/combinations_spec.rb +83 -0
  143. data/spec/lib/query/combinator_spec.rb +112 -0
  144. data/spec/lib/query/full_spec.rb +22 -0
  145. data/spec/lib/query/live_spec.rb +61 -0
  146. data/spec/lib/query/qualifiers_spec.rb +31 -0
  147. data/spec/lib/query/solr_spec.rb +51 -0
  148. data/spec/lib/query/token_spec.rb +297 -0
  149. data/spec/lib/query/tokens_spec.rb +189 -0
  150. data/spec/lib/query/weights_spec.rb +47 -0
  151. data/spec/lib/results/base_spec.rb +233 -0
  152. data/spec/lib/routing_spec.rb +318 -0
  153. data/spec/lib/solr/schema_generator_spec.rb +42 -0
  154. data/spec/lib/sources/db_spec.rb +91 -0
  155. data/spec/lib/tokenizers/base_spec.rb +61 -0
  156. data/spec/lib/tokenizers/index_spec.rb +51 -0
  157. data/spec/lib/tokenizers/query_spec.rb +105 -0
  158. data/spec/lib/umlaut_substituter_spec.rb +84 -0
  159. data/spec/specific/speed_spec.rb +55 -0
  160. metadata +371 -15
  161. data/README.textile +0 -9
@@ -0,0 +1,109 @@
1
+ module Index
2
+
3
+ # An index category holds a full and a partial index for a given field.
4
+ #
5
+ # For example an index category for names holds a full and
6
+ # a partial index bundle for names.
7
+ #
8
+ class Category
9
+
10
+ attr_reader :name, :type, :full, :partial
11
+
12
+ #
13
+ #
14
+ def initialize name, type, options = {}
15
+ @name = name
16
+ @type = type
17
+
18
+ partial = options[:partial] || Cacher::Partial::Default
19
+ weights = options[:weights] || Cacher::Weights::Default
20
+ similarity = options[:similarity] || Cacher::Similarity::Default
21
+
22
+ @full = options[:full_bundle] || Bundle.new(:full, self, type, Cacher::Partial::None.new, weights, similarity)
23
+ @partial = options[:partial_bundle] || Bundle.new(:partial, self, type, partial, weights, Cacher::Similarity::None.new)
24
+
25
+ @full = options[:full_lambda].call(@full, @partial) if options[:full_lambda]
26
+ @partial = options[:partial_lambda].call(@full, @partial) if options[:partial_lambda]
27
+ end
28
+
29
+ # Loads the index from cache.
30
+ #
31
+ def load_from_cache
32
+ full.load
33
+ partial.load
34
+ end
35
+
36
+ def identifier
37
+ "#{type.name}:#{name}"
38
+ end
39
+
40
+ # Generates all caches for this category.
41
+ #
42
+ def generate_caches
43
+ exclaim "#{Time.now}: Loading data from db for #{identifier}."
44
+ generate_caches_from_db
45
+ exclaim "#{Time.now}: Generating partial for #{identifier}."
46
+ generate_partial
47
+ exclaim "#{Time.now}: Generating caches from memory for #{identifier}."
48
+ generate_caches_from_memory
49
+ exclaim "#{Time.now}: Dumping all caches for #{identifier}."
50
+ dump_caches
51
+ end
52
+ def generate_caches_from_db
53
+ full.generate_caches_from_db
54
+ end
55
+ def generate_partial
56
+ partial.generate_partial_from full.index
57
+ end
58
+ def generate_caches_from_memory
59
+ partial.generate_caches_from_memory
60
+ end
61
+ def dump_caches
62
+ full.dump
63
+ partial.dump
64
+ end
65
+ def exclaim text
66
+ puts text
67
+ end
68
+
69
+ # Used for testing.
70
+ #
71
+ def generate_indexes_from_full_index
72
+ generate_derived_full
73
+ generate_partial
74
+ generate_derived_partial
75
+ end
76
+ def generate_derived_full
77
+ full.generate_derived
78
+ end
79
+ def generate_derived_partial
80
+ partial.generate_derived
81
+ end
82
+
83
+ # Gets the weight for this token's text.
84
+ #
85
+ def weight token
86
+ bundle_for(token).weight token.text
87
+ end
88
+
89
+ # Gets the ids for this token's text.
90
+ #
91
+ def ids token
92
+ bundle_for(token).ids token.text
93
+ end
94
+
95
+ # Returns the right index bundle for this token.
96
+ #
97
+ def bundle_for token
98
+ token.partial? ? partial : full
99
+ end
100
+
101
+ #
102
+ #
103
+ def combination_for token
104
+ weight(token) && ::Query::Combination.new(token, self)
105
+ end
106
+
107
+ end
108
+
109
+ end
@@ -0,0 +1,38 @@
1
+ # encoding: utf-8
2
+ #
3
+ module Index
4
+
5
+ #
6
+ #
7
+ class Combined < Bundle
8
+
9
+ delegate :similar,
10
+ :identifier,
11
+ :name,
12
+ :to => :@full
13
+ delegate :type,
14
+ :category,
15
+ :weight,
16
+ :generate_partial_from,
17
+ :generate_caches_from_memory,
18
+ :generate_derived,
19
+ :dump,
20
+ :load,
21
+ :to => :@partial
22
+
23
+ def initialize full, partial
24
+ @full = full
25
+ @partial = partial
26
+ end
27
+
28
+ def ids text
29
+ @full.ids(text) + @partial.ids(text)
30
+ end
31
+
32
+ def weight text
33
+ [@full.weight(text) || 0, @partial.weight(text) || 0].max
34
+ end
35
+
36
+ end
37
+
38
+ end
@@ -0,0 +1,30 @@
1
+ module Index
2
+
3
+ # This class is for multiple types.
4
+ #
5
+ # For example, you could have types books, isbn.
6
+ #
7
+ class Type
8
+
9
+ attr_reader :name, :result_type, :categories, :combinator
10
+
11
+ each_delegate :generate_caches, :load_from_cache, :to => :categories
12
+
13
+ # TODO Use config
14
+ #
15
+ def initialize name, result_type, ignore_unassigned_tokens, *categories
16
+ @name = name
17
+ @result_type = result_type # TODO Move.
18
+ @categories = categories # for each_delegate
19
+ @combinator = Query::Combinator.new @categories, :ignore_unassigned_tokens => ignore_unassigned_tokens # TODO pass this in?
20
+ end
21
+
22
+ #
23
+ #
24
+ def possible_combinations token
25
+ @combinator.possible_combinations_for token
26
+ end
27
+
28
+ end
29
+
30
+ end
@@ -0,0 +1,77 @@
1
+ # encoding: utf-8
2
+ module Indexers
3
+ # Indexer.
4
+ #
5
+ # 1. Gets data from the original table and copies it into a "snapshot table".
6
+ # 3. Processes the data. I.e. takes the snapshot table data words and tokenizes etc. them. Writes the result into a txt file.
7
+ #
8
+ class Base
9
+
10
+ def initialize type, field
11
+ @type = type
12
+ @field = field
13
+ end
14
+
15
+ # Convenience method for getting the right Tokenizer.
16
+ #
17
+ def tokenizer
18
+ @field.tokenizer
19
+ end
20
+ # Convenience methods for user subclasses.
21
+ #
22
+ def search_index_file_name
23
+ @field.search_index_file_name
24
+ end
25
+
26
+ # Executes the specific strategy.
27
+ #
28
+ def index
29
+ process
30
+ end
31
+
32
+ # Get the source where the data is taken from.
33
+ #
34
+ def source
35
+ @field.source || raise_no_source
36
+ end
37
+ def raise_no_source
38
+ raise NoSourceSpecifiedException.new "No source given for #{@type.name}:#{@field.name}."
39
+ end
40
+
41
+ # Selects the original id (indexed id) and a column to process. The column data is called "token".
42
+ #
43
+ def process
44
+ comma = ?,
45
+ newline = ?\n
46
+
47
+ File.open(search_index_file_name, 'w:binary') do |file|
48
+ chunked do |indexed_id, text|
49
+ tokenizer.tokenize(text).each do |token_text|
50
+ file.write indexed_id
51
+ file.write comma
52
+ file.write token_text
53
+ file.write newline
54
+ end
55
+ end
56
+ end
57
+ end
58
+ # Split original data into chunks.
59
+ #
60
+ def chunked
61
+ (0..source.count(@type)).step(chunksize) do |offset|
62
+ indexing_message offset
63
+ data = source.harvest @type, @field, offset, chunksize
64
+ data.each do |indexed_id, text|
65
+ next unless text
66
+ text.force_encoding 'utf-8' # TODO Still needed?
67
+ yield indexed_id, text
68
+ end
69
+ end
70
+ end
71
+
72
+ def indexing_message offset
73
+ puts "#{Time.now}: Indexing #{@type.name}:#{@field.name}:#{@field.indexed_name} beginning at #{offset}."
74
+ end
75
+
76
+ end
77
+ end
@@ -0,0 +1,3 @@
1
+ module Indexers
2
+ Default = Field
3
+ end
@@ -0,0 +1,13 @@
1
+ module Indexers
2
+ # Base indexer for fields.
3
+ #
4
+ class Field < Base
5
+
6
+ # Override in subclasses.
7
+ #
8
+ def chunksize
9
+ 25_000
10
+ end
11
+
12
+ end
13
+ end
@@ -0,0 +1,5 @@
1
+ module Indexers
2
+
3
+ class NoSourceSpecifiedException < StandardError; end
4
+
5
+ end
@@ -0,0 +1,60 @@
1
+ # encoding: utf-8
2
+ #
3
+ require 'rsolr'
4
+ module Indexers
5
+ # This is an indexer in its own right.
6
+ #
7
+ # TODO Perhaps merge with the existing indexer.
8
+ #
9
+ class Solr
10
+
11
+ attr_reader :type, :fields, :solr
12
+
13
+ # Takes a Configuration::Type.
14
+ #
15
+ def initialize type
16
+ @type = type
17
+ @fields = type.solr_fields.map(&:name).map(&:to_sym)
18
+ @solr = RSolr.connect
19
+ end
20
+
21
+ # TODO Rewrite such that it works in batches.
22
+ #
23
+ def index
24
+ puts "#{Time.now}: Indexing solr for #{type.name}:#{fields.join(', ')}"
25
+ statement = "SELECT indexed_id, #{fields.join(',')} FROM #{type.snapshot_table_name}"
26
+
27
+ # TODO Rewrite.
28
+ #
29
+ DB.connect
30
+ results = DB.connection.execute statement
31
+
32
+ return unless results # TODO check
33
+
34
+ type_name = @type.name.to_s
35
+
36
+ solr.delete_by_query "type:#{type_name}"
37
+ solr.commit
38
+
39
+ documents = []
40
+
41
+ results.each do |indexed_id, *values|
42
+ values.each &:downcase!
43
+ documents << hashed(values).merge(:id => indexed_id, :type => type_name)
44
+ end
45
+
46
+ solr.add documents
47
+ solr.commit
48
+ solr.optimize
49
+ end
50
+
51
+ def hashed values
52
+ result = {}
53
+ fields.zip(values).each do |field, value|
54
+ result[field] = value
55
+ end
56
+ result
57
+ end
58
+
59
+ end
60
+ end
@@ -0,0 +1,180 @@
1
+ module Indexes
2
+
3
+ mattr_accessor :configuration, :types, :type_mapping
4
+
5
+ # Takes a snapshot of the originating table.
6
+ #
7
+ def self.take_snapshot *args
8
+ configuration.take_snapshot *args
9
+ end
10
+ # Runs the indexers in parallel (index + cache).
11
+ #
12
+ def self.index
13
+ Indexes.take_snapshot
14
+
15
+ # Run in parallel.
16
+ #
17
+ puts "Indexing using #{Cores.max_processors} processors."
18
+ Cores.forked self.fields, :randomly => true do |field|
19
+ # Reestablish DB connection.
20
+ DB.connect # TODO Rewrite!
21
+ field.index
22
+ field.cache
23
+ end
24
+ end
25
+ def self.index_solr
26
+ configuration.index_solr
27
+ end
28
+
29
+ # Returns an array of fields.
30
+ #
31
+ # TODO Rewrite.
32
+ #
33
+ def self.fields
34
+ result = []
35
+ configuration.types.each do |type|
36
+ type.fields.inject(result) do |total, field|
37
+ total << field
38
+ end
39
+ end
40
+ result
41
+ end
42
+
43
+ #
44
+ #
45
+ # TODO Rewrite.
46
+ #
47
+ def self.find type_name, field_name
48
+ type_name = type_name.to_sym
49
+ field_name = field_name.to_sym
50
+ configuration.types.each do |type|
51
+ next unless type.name == type_name
52
+ type.fields.each do |field|
53
+ next unless field.name == field_name
54
+ return field
55
+ end
56
+ end
57
+ end
58
+
59
+ # Backup / Restore.
60
+ #
61
+ def self.backup_caches
62
+ each_category do |category|
63
+ category.full.backup
64
+ category.partial.backup
65
+ end
66
+ end
67
+ def self.restore_caches
68
+ each_category do |category|
69
+ category.full.restore
70
+ category.partial.restore
71
+ end
72
+ end
73
+
74
+ # Use these if you need to index / cache a single index.
75
+ #
76
+ def self.generate_index_only type_name, field_name
77
+ Indexes.configuration.types.each do |type|
78
+ next unless type_name == type.name
79
+ type.fields.each do |field|
80
+ field.index if field_name == field.name
81
+ end
82
+ end
83
+ end
84
+ def self.generate_cache_only type_name, category_name
85
+ Indexes.each do |type|
86
+ next unless type_name == type.name
87
+ type.categories.each do |category|
88
+ category.generate_caches if category_name == category.name
89
+ end
90
+ end
91
+ end
92
+
93
+ # Runs the index cache generation.
94
+ #
95
+ # TODO Needed?
96
+ #
97
+ def self.generate_caches
98
+ each &:generate_caches
99
+ end
100
+ # Loads all indexes from the caches.
101
+ #
102
+ def self.load_from_cache
103
+ each &:load_from_cache
104
+ end
105
+ def self.reload
106
+ load_from_cache
107
+ end
108
+
109
+ # Checks if the caches are there.
110
+ #
111
+ def self.check_caches
112
+ each do |type|
113
+ type.categories.each do |category|
114
+ category.full.raise_unless_cache_exists
115
+ category.partial.raise_unless_cache_exists
116
+ end
117
+ end
118
+ end
119
+
120
+ # Removes the cache files.
121
+ #
122
+ def self.clear_caches
123
+ each do |type|
124
+ type.categories.each do |category|
125
+ category.full.delete_all
126
+ category.partial.delete_all
127
+ end
128
+ end
129
+ end
130
+
131
+ # Creates the directory structure for the indexes.
132
+ #
133
+ # TODO Should be on type?
134
+ #
135
+ def self.create_directory_structure
136
+ each_bundle do |full, partial|
137
+ full.create_directory
138
+ partial.create_directory
139
+ end
140
+ end
141
+
142
+ #
143
+ #
144
+ def self.clear
145
+ self.types = []
146
+ end
147
+
148
+
149
+ def self.each &block
150
+ types.each &block
151
+ end
152
+ def self.each_category &block
153
+ each do |type|
154
+ type.categories.each &block
155
+ end
156
+ end
157
+ def self.each_bundle
158
+ each_category do |category|
159
+ yield category.full, category.partial
160
+ end
161
+ end
162
+
163
+ # Loads all index definitions.
164
+ #
165
+ def self.setup
166
+ self.types ||= []
167
+ self.type_mapping ||= {}
168
+ configuration.types.each do |type|
169
+ add type.generate
170
+ end
171
+ end
172
+ def self.add type
173
+ self.type_mapping[type.name] = type
174
+ self.types << type
175
+ end
176
+ def self.[] type_name
177
+ self.type_mapping[type_name]
178
+ end
179
+
180
+ end
@@ -0,0 +1,6 @@
1
+ # TODO What to do with this?
2
+ #
3
+ Dir.chdir File.join(File.dirname(__FILE__), '../ext/ruby19') do
4
+ %x{ ruby extconf.rb && make }
5
+ end
6
+ require File.expand_path(File.join(File.dirname(__FILE__), '../ext/ruby19/performant'))
@@ -0,0 +1,22 @@
1
+ # Wrapper for the mysql adapter method execute
2
+ # to handle the 8 hours disconnect problem.
3
+ # (http://www.mysql.fr/search/?q=autoreconnect)
4
+ #
5
+ ActiveRecord::ConnectionAdapters::MysqlAdapter.module_eval do
6
+ def execute_with_retry_once(sql, name = nil)
7
+ retried = false
8
+ begin
9
+ execute_without_retry_once(sql, name)
10
+ rescue ActiveRecord::StatementInvalid => statement_invalid_exception
11
+ # Our database connection has gone away, reconnect and retry this method
12
+ #
13
+ reconnect!
14
+ unless retried
15
+ retried = true
16
+ retry
17
+ end
18
+ end
19
+ end
20
+
21
+ alias_method_chain :execute, :retry_once
22
+ end