picky 0.0.0 → 0.0.2

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.
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