ts-delayed-delta 1.1.3 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. data/.gitignore +1 -0
  2. data/.travis.yml +14 -12
  3. data/Appraisals +11 -0
  4. data/Gemfile +1 -3
  5. data/LICENSE +1 -1
  6. data/README.textile +29 -26
  7. data/Rakefile +3 -16
  8. data/gemfiles/binary.gemfile +7 -0
  9. data/gemfiles/sphinxql.gemfile +7 -0
  10. data/lib/thinking_sphinx/deltas/delayed_delta.rb +117 -47
  11. data/lib/thinking_sphinx/deltas/delayed_delta/delta_job.rb +7 -16
  12. data/lib/thinking_sphinx/deltas/delayed_delta/flag_as_deleted_job.rb +8 -19
  13. data/lib/ts-delayed-delta.rb +0 -3
  14. data/spec/acceptance/delayed_job_deltas_spec.rb +46 -0
  15. data/spec/acceptance/spec_helper.rb +4 -0
  16. data/spec/acceptance/support/database_cleaner.rb +11 -0
  17. data/spec/acceptance/support/sphinx_controller.rb +61 -0
  18. data/spec/acceptance/support/sphinx_helpers.rb +31 -0
  19. data/spec/internal/.gitignore +2 -0
  20. data/spec/internal/app/indices/book_index.rb +3 -0
  21. data/spec/internal/app/models/book.rb +7 -0
  22. data/spec/internal/config/database.yml +5 -0
  23. data/spec/internal/db/schema.rb +24 -0
  24. data/spec/internal/log/.gitignore +1 -0
  25. data/spec/spec_helper.rb +9 -7
  26. data/ts-delayed-delta.gemspec +15 -11
  27. metadata +129 -86
  28. data/VERSION +0 -1
  29. data/features/delayed_deltas.feature +0 -37
  30. data/features/step_definitions/common_steps.rb +0 -48
  31. data/features/step_definitions/delayed_delta_steps.rb +0 -11
  32. data/features/support/env.rb +0 -33
  33. data/features/thinking_sphinx/database.example.yml +0 -3
  34. data/features/thinking_sphinx/db/fixtures/delayed_betas.rb +0 -10
  35. data/features/thinking_sphinx/db/migrations/create_delayed_betas.rb +0 -17
  36. data/features/thinking_sphinx/models/delayed_beta.rb +0 -7
  37. data/lib/thinking_sphinx/deltas/delayed_delta/job.rb +0 -65
  38. data/lib/thinking_sphinx/deltas/delayed_delta/railtie.rb +0 -5
  39. data/lib/thinking_sphinx/deltas/delayed_delta/tasks.rb +0 -23
  40. data/lib/thinking_sphinx/deltas/delayed_delta/version.rb +0 -5
  41. data/spec/thinking_sphinx/deltas/delayed_delta/delta_job_spec.rb +0 -53
  42. data/spec/thinking_sphinx/deltas/delayed_delta/flag_as_deleted_job_spec.rb +0 -78
  43. data/spec/thinking_sphinx/deltas/delayed_delta/job_spec.rb +0 -52
  44. data/spec/thinking_sphinx/deltas/delayed_delta_spec.rb +0 -128
  45. data/tasks/rails.rake +0 -1
data/.gitignore CHANGED
@@ -18,6 +18,7 @@ coverage
18
18
  rdoc
19
19
  pkg
20
20
  Gemfile.lock
21
+ gemfiles/*.gemfile.lock
21
22
 
22
23
  ## PROJECT::SPECIFIC
23
24
  features/thinking_sphinx/database.yml
data/.travis.yml CHANGED
@@ -1,16 +1,18 @@
1
+ language: ruby
1
2
  rvm:
2
- # - 1.8.6
3
- - 1.8.7
4
3
  - 1.9.2
5
4
  - 1.9.3
6
- - rbx
7
- - rbx-2.0
8
- - ree
9
- # - jruby
10
- # - ruby-head
11
- # env:
12
- # - SPHINX_BIN=/usr/local/sphinx-0.9.9/bin SPHINX_VERSION=0.9.9
13
- # - SPHINX_BIN=/usr/local/sphinx-1.10/bin SPHINX_VERSION=1.10
14
- # - SPHINX_BIN=/usr/local/sphinx-2.0.1/bin SPHINX_VERSION=2.0.1
5
+ before_install:
6
+ - gem update --system
7
+ - gem install bundler --no-ri --no-rdoc
8
+ - curl -O http://fs-packages.s3.amazonaws.com/fs-sphinx-2.0.6_x86_64_12.04.deb
9
+ - sudo dpkg -i fs-sphinx-2.0.6_x86_64_12.04.deb
10
+ - bundle install
15
11
  before_script:
16
- - "mysql -e 'create database thinking_sphinx;' > /dev/null"
12
+ - "mysql -e 'create database thinking_sphinx;' > /dev/null"
13
+ - "psql -c 'create database thinking_sphinx;' -U postgres > /dev/null"
14
+ - "bundle exec rake appraisal:install"
15
+ env:
16
+ - SPHINX_BIN=/usr/local/sphinx-2.0.6/bin/ SPHINX_VERSION=2.0.6 DATABASE=mysql2
17
+ - SPHINX_BIN=/usr/local/sphinx-2.0.6/bin/ SPHINX_VERSION=2.0.6 DATABASE=postgresql
18
+ script: "bundle exec rake appraisal spec"
data/Appraisals ADDED
@@ -0,0 +1,11 @@
1
+ appraise "binary" do
2
+ gem 'thinking-sphinx',
3
+ :git => 'git://github.com/pat/thinking-sphinx.git',
4
+ :ref => '94851c0e6b'
5
+ end
6
+
7
+ appraise "sphinxql" do
8
+ gem 'thinking-sphinx',
9
+ :git => 'git://github.com/pat/thinking-sphinx.git',
10
+ :ref => '86ac3edfbe'
11
+ end
data/Gemfile CHANGED
@@ -1,5 +1,3 @@
1
- source :rubygems
1
+ source 'https://rubygems.org'
2
2
 
3
3
  gemspec
4
-
5
- gem 'rcov', '>= 0.9.8', :platform => :ruby_18
data/LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2009 Pat Allan
1
+ Copyright (c) 2009-2012 Pat Allan
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
data/README.textile CHANGED
@@ -2,48 +2,49 @@ h1. Delayed Deltas for Thinking Sphinx
2
2
 
3
3
  h2. Installation
4
4
 
5
- You'll need Thinking Sphinx 1.3.0 or later, and Delayed Job as well. The latter is flagged as a dependency.
5
+ This version requires Thinking Sphinx 3.x (currently the edge branch) and Delayed Job 3.x.
6
6
 
7
- <pre><code>gem install ts-delayed-delta --source http://gemcutter.org</code></pre>
7
+ In your @Gemfile@, it'll likely look something like this:
8
8
 
9
- In your @environment.rb@ file, with the rest of your gem dependencies:
9
+ <pre><code>gem 'ts-delayed-delta', '~> 2.0.0'</code></pre>
10
10
 
11
- <pre><code>config.gem 'ts-delayed-delta',
12
- :lib => 'thinking_sphinx/deltas/delayed_delta',
13
- :version => '>= 1.0.0',
14
- :source => 'http://gemcutter.org'</code></pre>
11
+ Or, if you're referring directly to the git repository:
15
12
 
16
- And add the following line to the bottom of your @Rakefile@ if you're not using Rails 3 or newer:
13
+ <pre><code>gem 'ts-delayed-delta',
14
+ :git => 'git://github.com/pat/ts-delayed-delta.git',
15
+ :branch => 'edge',
16
+ :ref => 'use-latest-commit-here'</code></pre>
17
17
 
18
- <pre><code>require 'thinking_sphinx/deltas/delayed_delta/tasks'</code></pre>
18
+ And given this gem's built for Delayed Job, we're presuming you've got that set up (with the database table), and you know how to run it. This gem no longer provides a custom task for that purpose - there's no need.
19
19
 
20
- If this is your first time running Delayed Job, then you're going to need the jobs table migration as well:
21
-
22
- <pre><code>script/generate delayed_job</code></pre>
20
+ h2. Usage
23
21
 
24
- For the indices you want to use this delta approach, make sure you set that up in their @define_index@ blocks.
22
+ In your index definitions, make sure you set the @:delta@ setting to @ThinkingSphinx::Deltas::DelayedDelta@:
25
23
 
26
- <pre><code>define_index do
24
+ <pre><code>ThinkingSphinx::Index.define :book, :with => :active_record, :delta => ThinkingSphinx::Deltas::DelayedDelta do
27
25
  # ...
28
-
29
- set_property :delta => :delayed
30
26
  end</code></pre>
31
27
 
32
- If you've never used delta indices before, you'll want to add the boolean column named delta to each model that is using the approach.
28
+ If you've never used delta indices before, you'll want to add the boolean column named delta to each model that is using the approach. It probably doesn't hurt to add an index to that column as well.
33
29
 
34
- <pre><code>def self.up
35
- add_column :articles, :delta, :boolean, :default => true, :null => false
36
- end</code></pre>
30
+ <pre><code>add_column :books, :delta, :boolean, :default => true, :null => false
31
+ add_index :books, :delta</code></pre>
37
32
 
38
- h2. Usage
33
+ And that's pretty much it. Make sure Delayed Job is running, and it'll take care of the jobs to keep your Sphinx indices up to date.
34
+
35
+ Please keep in mind that you need to run the Delayed Job workers on the same machine as Sphinx, as direct access to Sphinx files (and the Sphinx command-line tools) is essential.
36
+
37
+ h2. Limitations
39
38
 
40
- Once you've got it all set up, all you need to do is make sure that the delayed job process is running - either by Delayed Job's built-in approach, or Thinking Sphinx's custom rake task:
39
+ This version of the gem is built for Ruby 1.9 and Rails 3.1 or newer, just like Thinking Sphinx 3.
41
40
 
42
- <pre><code>rake thinking_sphinx:delayed_delta</code></pre>
41
+ h2. Contributing
43
42
 
44
- There's also a short name for the same task, to save your fingers some effort:
43
+ Contributions are very much welcome - but keep in mind the following:
45
44
 
46
- <pre><code>rake ts:dd</code></pre>
45
+ * Keep patches in a separate branch
46
+ * Don't mess with the version number. I'll take care of that when the patch is merged in.
47
+ * Please write tests - currently, there's only acceptance tests in place, because the underlying code is simple enough. If you get stuck into anything complex, unit tests are a smart move.
47
48
 
48
49
  h2. Contributors
49
50
 
@@ -56,7 +57,9 @@ h2. Contributors
56
57
  * "Reinier de Lange":http://www.nedforce.nl/ (Fix for table name reference)
57
58
  * "Enrico Brunetta":http://github.com/enrico (Adding Railtie for Rails 3)
58
59
  * "Jonathan Viney":https://github.com/jviney and "James Healy":http://yob.id.au/ (Rails 3.2 deprecation fixes)
60
+ * "Georg Ledermann":http://www.georg-ledermann.de (DJ 2.0.x backwards compatibility)
61
+ * "Jonathan Lim":http://snowblink.co.uk (Cleaning up version references)
59
62
 
60
63
  h2. Copyright
61
64
 
62
- Copyright (c) 2009-2010 Pat Allan, and released under an MIT Licence.
65
+ Copyright (c) 2009-2012, Thinking Sphinx Delayed Deltas (ts-delayed-delta) is developed and maintained by Pat Allan, and is released under the open MIT Licence. Many thanks to "all who have contributed patches":https://github.com/pat/ts-delayed-delta/contributors.
data/Rakefile CHANGED
@@ -1,23 +1,10 @@
1
- require 'rubygems'
2
- require 'bundler'
1
+ require 'bundler/setup'
3
2
 
4
3
  Bundler::GemHelper.install_tasks
5
- Bundler.require :default, :development
6
4
 
5
+ require 'appraisal'
7
6
  require 'rspec/core/rake_task'
8
- require 'cucumber/rake/task'
9
7
 
10
8
  RSpec::Core::RakeTask.new
11
9
 
12
- RSpec::Core::RakeTask.new(:rcov) do |spec|
13
- spec.rcov_opts = ['--exclude', 'spec', '--exclude', 'gems']
14
- spec.rcov = true
15
- end
16
-
17
- Cucumber::Rake::Task.new do |task|
18
- task.cucumber_opts = '--exclude features/thinking_sphinx'
19
- end
20
-
21
- YARD::Rake::YardocTask.new
22
-
23
- task :default => [:spec, :cucumber]
10
+ task :default => :spec
@@ -0,0 +1,7 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "thinking-sphinx", :git=>"git://github.com/pat/thinking-sphinx.git", :ref=>"94851c0e6b"
6
+
7
+ gemspec :path=>"../"
@@ -0,0 +1,7 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "thinking-sphinx", :git=>"git://github.com/pat/thinking-sphinx.git", :ref=>"86ac3edfbe"
6
+
7
+ gemspec :path=>"../"
@@ -1,10 +1,5 @@
1
1
  require 'delayed_job'
2
-
3
2
  require 'thinking_sphinx'
4
- require 'thinking_sphinx/deltas/delayed_delta/delta_job'
5
- require 'thinking_sphinx/deltas/delayed_delta/flag_as_deleted_job'
6
- require 'thinking_sphinx/deltas/delayed_delta/job'
7
- require 'thinking_sphinx/deltas/delayed_delta/version'
8
3
 
9
4
  # Delayed Deltas for Thinking Sphinx, using Delayed Job.
10
5
  #
@@ -16,52 +11,127 @@ require 'thinking_sphinx/deltas/delayed_delta/version'
16
11
  # @author Patrick Allan
17
12
  # @see http://ts.freelancing-gods.com Thinking Sphinx
18
13
  #
19
- class ThinkingSphinx::Deltas::DelayedDelta < ThinkingSphinx::Deltas::DefaultDelta
20
-
21
- # Adds a job to the queue for processing the given model's delta index. A job
22
- # for hiding the instance in the core index is also created, if an instance is
23
- # provided.
24
- #
25
- # Neither job will be queued if updates or deltas are disabled, or if the
26
- # instance (when given) is not toggled to be in the delta index. The first two
27
- # options are controlled via ThinkingSphinx.updates_enabled? and
28
- # ThinkingSphinx.deltas_enabled?.
29
- #
30
- # @param [Class] model the ActiveRecord model to index.
31
- # @param [ActiveRecord::Base] instance the instance of the given model that
32
- # has changed. Optional.
33
- # @return [Boolean] true
34
- #
35
- def index(model, instance = nil)
36
- return true if skip? instance
37
- return true if instance && !toggled(instance)
38
-
39
- ThinkingSphinx::Deltas::Job.enqueue(
40
- ThinkingSphinx::Deltas::DeltaJob.new(model.delta_index_names),
41
- ThinkingSphinx::Configuration.instance.delayed_job_priority
14
+ class ThinkingSphinx::Deltas::DelayedDelta <
15
+ ThinkingSphinx::Deltas::DefaultDelta
16
+
17
+ def self.cancel_jobs
18
+ Delayed::Job.delete_all(
19
+ "handler LIKE '--- !ruby/object:ThinkingSphinx::Deltas::%'"
42
20
  )
21
+ end
22
+
23
+ def self.enqueue_unless_duplicates(object)
24
+ if Delayed::Job.respond_to?(:where)
25
+ return if Delayed::Job.where(
26
+ :handler => object.to_yaml, :locked_at => nil
27
+ ).count > 0
28
+ else
29
+ return if Delayed::Job.count(
30
+ :conditions => {:handler => object.to_yaml, :locked_at => nil}
31
+ ) > 0
32
+ end
43
33
 
44
- Delayed::Job.enqueue(
45
- ThinkingSphinx::Deltas::FlagAsDeletedJob.new(
46
- model.core_index_names, instance.sphinx_document_id
47
- ),
48
- :priority => ThinkingSphinx::Configuration.instance.delayed_job_priority
49
- ) if instance
34
+ Delayed::Job.enqueue object, priority_option
35
+ end
50
36
 
51
- true
37
+ def self.priority_option
38
+ if Gem.loaded_specs['delayed_job'].version.to_s.match(/^2\.0\./)
39
+ # Fallback for compatibility with old release 2.0.x of DJ
40
+ priority
41
+ else
42
+ {:priority => priority}
43
+ end
52
44
  end
53
45
 
54
- private
55
-
56
- # Checks whether jobs should be enqueued. Only true if updates and deltas are
57
- # enabled, and the instance (if there is one) is toggled.
58
- #
59
- # @param [ActiveRecord::Base, NilClass] instance
60
- # @return [Boolean]
61
- #
62
- def skip?(instance)
63
- !ThinkingSphinx.updates_enabled? ||
64
- !ThinkingSphinx.deltas_enabled? ||
65
- (instance && !toggled(instance))
46
+ def self.priority
47
+ configuration = ThinkingSphinx::Configuration.instance
48
+ if configuration.respond_to? :delayed_job_priority
49
+ configuration.delayed_job_priority
50
+ else
51
+ configuration.settings['delayed_job_priority'] || 0
52
+ end
53
+ end
54
+
55
+ module Binary
56
+ # Adds a job to the queue for processing the given model's delta index. A job
57
+ # for hiding the instance in the core index is also created, if an instance is
58
+ # provided.
59
+ #
60
+ # Neither job will be queued if updates or deltas are disabled, or if the
61
+ # instance (when given) is not toggled to be in the delta index. The first two
62
+ # options are controlled via ThinkingSphinx.updates_enabled? and
63
+ # ThinkingSphinx.deltas_enabled?.
64
+ #
65
+ # @param [Class] model the ActiveRecord model to index.
66
+ # @param [ActiveRecord::Base] instance the instance of the given model that
67
+ # has changed. Optional.
68
+ # @return [Boolean] true
69
+ #
70
+ def index(model, instance = nil)
71
+ return true if skip? instance
72
+
73
+ self.class.enqueue_unless_duplicates(
74
+ ThinkingSphinx::Deltas::DelayedDelta::DeltaJob.new(
75
+ model.delta_index_names
76
+ )
77
+ )
78
+
79
+ Delayed::Job.enqueue(
80
+ ThinkingSphinx::Deltas::DelayedDelta::FlagAsDeletedJob.new(
81
+ model.core_index_names, instance.sphinx_document_id
82
+ ), self.class.priority_option
83
+ ) if instance
84
+
85
+ true
86
+ end
87
+
88
+ private
89
+
90
+ # Checks whether jobs should be enqueued. Only true if updates and deltas are
91
+ # enabled, and the instance (if there is one) is toggled.
92
+ #
93
+ # @param [ActiveRecord::Base, NilClass] instance
94
+ # @return [Boolean]
95
+ #
96
+ def skip?(instance)
97
+ !ThinkingSphinx.updates_enabled? ||
98
+ !ThinkingSphinx.deltas_enabled? ||
99
+ (instance && !toggled(instance))
100
+ end
101
+ end
102
+
103
+ module SphinxQL
104
+ def delete(index, instance)
105
+ Delayed::Job.enqueue(
106
+ ThinkingSphinx::Deltas::DelayedDelta::FlagAsDeletedJob.new(
107
+ index.name, index.document_id_for_key(instance.id)
108
+ ), self.class.priority_option
109
+ )
110
+ end
111
+
112
+ # Adds a job to the queue for processing the given index.
113
+ #
114
+ # @param [Class] index the Thinking Sphinx index object.
115
+ #
116
+ def index(index)
117
+ self.class.enqueue_unless_duplicates(
118
+ ThinkingSphinx::Deltas::DelayedDelta::DeltaJob.new(index.name)
119
+ )
120
+ end
121
+ end
122
+
123
+ if [:delayed_job_priority, 'delayed_job_priority'].any? { |method|
124
+ ThinkingSphinx::Configuration.instance_methods.include?(method)
125
+ }
126
+ include Binary
127
+ else
128
+ include SphinxQL
66
129
  end
67
130
  end
131
+
132
+ require 'thinking_sphinx/deltas/delayed_delta/delta_job'
133
+ require 'thinking_sphinx/deltas/delayed_delta/flag_as_deleted_job'
134
+
135
+ ThinkingSphinx.before_index_hooks << Proc.new {
136
+ ThinkingSphinx::Deltas::DelayedDelta.cancel_jobs
137
+ }
@@ -1,33 +1,24 @@
1
1
  # A simple job class that processes a given index.
2
2
  #
3
- class ThinkingSphinx::Deltas::DeltaJob
4
- attr_accessor :indices
5
-
3
+ class ThinkingSphinx::Deltas::DelayedDelta::DeltaJob
6
4
  # Initialises the object with an index name.
7
5
  #
8
6
  # @param [String] index the name of the Sphinx index
9
7
  #
10
- def initialize(indices)
11
- @indices = indices
8
+ def initialize(index)
9
+ @index = index
12
10
  end
13
11
 
14
12
  # Shows index name in Delayed::Job#name.
15
13
  #
16
14
  def display_name
17
- "#{self.class.name} for #{indices.join(', ')}"
15
+ "Thinking Sphinx: Process #{@index}"
18
16
  end
19
17
 
20
- # Runs Sphinx's indexer tool to process the index. Currently assumes Sphinx is
21
- # running.
22
- #
23
- # @return [Boolean] true
18
+ # Processes just the given index. Output is hidden only if the quiet_deltas
19
+ # setting is true.
24
20
  #
25
21
  def perform
26
- config = ThinkingSphinx::Configuration.instance
27
-
28
- output = `#{config.bin_path}#{config.indexer_binary_name} --config "#{config.config_file}" --rotate #{indices.join(' ')}`
29
- puts output unless ThinkingSphinx.suppress_delta_output?
30
-
31
- true
22
+ ThinkingSphinx::Deltas::IndexJob.new(@index).perform
32
23
  end
33
24
  end
@@ -1,9 +1,7 @@
1
1
  # A simple job for flagging a specified Sphinx document in a given index as
2
2
  # 'deleted'.
3
3
  #
4
- class ThinkingSphinx::Deltas::FlagAsDeletedJob
5
- attr_accessor :indices, :document_id
6
-
4
+ class ThinkingSphinx::Deltas::DelayedDelta::FlagAsDeletedJob
7
5
  # Initialises the object with an index name and document id. Please note that
8
6
  # the document id is Sphinx's unique identifier, and will almost certainly not
9
7
  # be the model instance's primary key value.
@@ -11,8 +9,12 @@ class ThinkingSphinx::Deltas::FlagAsDeletedJob
11
9
  # @param [String] index The index name
12
10
  # @param [Integer] document_id The document id
13
11
  #
14
- def initialize(indices, document_id)
15
- @indices, @document_id = indices, document_id
12
+ def initialize(index, document_id)
13
+ @index, @document_id = index, document_id
14
+ end
15
+
16
+ def display_name
17
+ "Thinking Sphinx: Mark #{@document_id} in #{@index} as deleted"
16
18
  end
17
19
 
18
20
  # Updates the sphinx_deleted attribute for the given document, setting the
@@ -21,20 +23,7 @@ class ThinkingSphinx::Deltas::FlagAsDeletedJob
21
23
  # particularly useful in this situation to avoid old values in the core index
22
24
  # and just use the new values in the delta index as a reference point.
23
25
  #
24
- # @return [Boolean] true
25
- #
26
26
  def perform
27
- config = ThinkingSphinx::Configuration.instance
28
-
29
- indices.each do |index|
30
- config.client.update(
31
- index,
32
- ['sphinx_deleted'],
33
- {@document_id => [1]}
34
- ) if ThinkingSphinx.sphinx_running? &&
35
- ThinkingSphinx.search_for_id(@document_id, index)
36
- end
37
-
38
- true
27
+ ThinkingSphinx::Deltas::DeleteJob.new(@index, @document_id).perform
39
28
  end
40
29
  end