cehoffman-acts_as_ferret 0.4.4
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/LICENSE +20 -0
- data/README +68 -0
- data/bin/aaf_install +23 -0
- data/config/ferret_server.yml +24 -0
- data/doc/README.win32 +23 -0
- data/doc/demo/README +154 -0
- data/doc/demo/README_DEMO +23 -0
- data/doc/demo/Rakefile +10 -0
- data/doc/demo/app/controllers/admin/backend_controller.rb +14 -0
- data/doc/demo/app/controllers/admin_area_controller.rb +4 -0
- data/doc/demo/app/controllers/application.rb +5 -0
- data/doc/demo/app/controllers/contents_controller.rb +49 -0
- data/doc/demo/app/controllers/searches_controller.rb +8 -0
- data/doc/demo/app/helpers/admin/backend_helper.rb +2 -0
- data/doc/demo/app/helpers/application_helper.rb +3 -0
- data/doc/demo/app/helpers/content_helper.rb +2 -0
- data/doc/demo/app/helpers/search_helper.rb +2 -0
- data/doc/demo/app/models/comment.rb +48 -0
- data/doc/demo/app/models/content.rb +12 -0
- data/doc/demo/app/models/content_base.rb +28 -0
- data/doc/demo/app/models/search.rb +19 -0
- data/doc/demo/app/models/shared_index1.rb +3 -0
- data/doc/demo/app/models/shared_index2.rb +3 -0
- data/doc/demo/app/models/special_content.rb +3 -0
- data/doc/demo/app/models/stats.rb +20 -0
- data/doc/demo/app/views/admin/backend/search.rhtml +18 -0
- data/doc/demo/app/views/contents/_form.rhtml +10 -0
- data/doc/demo/app/views/contents/edit.rhtml +9 -0
- data/doc/demo/app/views/contents/index.rhtml +24 -0
- data/doc/demo/app/views/contents/new.rhtml +8 -0
- data/doc/demo/app/views/contents/show.rhtml +8 -0
- data/doc/demo/app/views/layouts/application.html.erb +17 -0
- data/doc/demo/app/views/searches/_content.html.erb +2 -0
- data/doc/demo/app/views/searches/search.html.erb +20 -0
- data/doc/demo/config/boot.rb +109 -0
- data/doc/demo/config/database.yml +38 -0
- data/doc/demo/config/environment.rb +69 -0
- data/doc/demo/config/environments/development.rb +16 -0
- data/doc/demo/config/environments/production.rb +19 -0
- data/doc/demo/config/environments/test.rb +21 -0
- data/doc/demo/config/ferret_server.yml +18 -0
- data/doc/demo/config/lighttpd.conf +40 -0
- data/doc/demo/config/routes.rb +9 -0
- data/doc/demo/db/development_structure.sql +15 -0
- data/doc/demo/db/migrate/001_initial_migration.rb +18 -0
- data/doc/demo/db/migrate/002_add_type_to_contents.rb +9 -0
- data/doc/demo/db/migrate/003_create_shared_index1s.rb +11 -0
- data/doc/demo/db/migrate/004_create_shared_index2s.rb +11 -0
- data/doc/demo/db/migrate/005_special_field.rb +9 -0
- data/doc/demo/db/migrate/006_create_stats.rb +15 -0
- data/doc/demo/db/schema.sql +18 -0
- data/doc/demo/doc/README_FOR_APP +2 -0
- data/doc/demo/doc/howto.txt +70 -0
- data/doc/demo/public/.htaccess +40 -0
- data/doc/demo/public/404.html +8 -0
- data/doc/demo/public/500.html +8 -0
- data/doc/demo/public/dispatch.cgi +10 -0
- data/doc/demo/public/dispatch.fcgi +24 -0
- data/doc/demo/public/dispatch.rb +10 -0
- data/doc/demo/public/favicon.ico +0 -0
- data/doc/demo/public/images/rails.png +0 -0
- data/doc/demo/public/index.html +277 -0
- data/doc/demo/public/robots.txt +1 -0
- data/doc/demo/public/stylesheets/scaffold.css +74 -0
- data/doc/demo/script/about +3 -0
- data/doc/demo/script/breakpointer +3 -0
- data/doc/demo/script/console +3 -0
- data/doc/demo/script/destroy +3 -0
- data/doc/demo/script/ferret_server +10 -0
- data/doc/demo/script/generate +3 -0
- data/doc/demo/script/performance/benchmarker +3 -0
- data/doc/demo/script/performance/profiler +3 -0
- data/doc/demo/script/plugin +3 -0
- data/doc/demo/script/process/inspector +3 -0
- data/doc/demo/script/process/reaper +3 -0
- data/doc/demo/script/process/spawner +3 -0
- data/doc/demo/script/process/spinner +3 -0
- data/doc/demo/script/runner +3 -0
- data/doc/demo/script/server +3 -0
- data/doc/demo/test/fixtures/comments.yml +12 -0
- data/doc/demo/test/fixtures/contents.yml +13 -0
- data/doc/demo/test/fixtures/remote_contents.yml +9 -0
- data/doc/demo/test/fixtures/shared_index1s.yml +7 -0
- data/doc/demo/test/fixtures/shared_index2s.yml +7 -0
- data/doc/demo/test/functional/admin/backend_controller_test.rb +35 -0
- data/doc/demo/test/functional/contents_controller_test.rb +81 -0
- data/doc/demo/test/functional/searches_controller_test.rb +71 -0
- data/doc/demo/test/smoke/drb_smoke_test.rb +321 -0
- data/doc/demo/test/smoke/process_stats.rb +21 -0
- data/doc/demo/test/test_helper.rb +30 -0
- data/doc/demo/test/unit/comment_test.rb +217 -0
- data/doc/demo/test/unit/content_test.rb +705 -0
- data/doc/demo/test/unit/ferret_result_test.rb +24 -0
- data/doc/demo/test/unit/multi_index_test.rb +329 -0
- data/doc/demo/test/unit/remote_index_test.rb +23 -0
- data/doc/demo/test/unit/shared_index1_test.rb +108 -0
- data/doc/demo/test/unit/shared_index2_test.rb +13 -0
- data/doc/demo/test/unit/sort_test.rb +21 -0
- data/doc/demo/test/unit/special_content_test.rb +25 -0
- data/doc/demo/vendor/plugins/will_paginate/LICENSE +18 -0
- data/doc/demo/vendor/plugins/will_paginate/README +108 -0
- data/doc/demo/vendor/plugins/will_paginate/Rakefile +23 -0
- data/doc/demo/vendor/plugins/will_paginate/init.rb +21 -0
- data/doc/demo/vendor/plugins/will_paginate/lib/will_paginate/collection.rb +45 -0
- data/doc/demo/vendor/plugins/will_paginate/lib/will_paginate/core_ext.rb +44 -0
- data/doc/demo/vendor/plugins/will_paginate/lib/will_paginate/finder.rb +159 -0
- data/doc/demo/vendor/plugins/will_paginate/lib/will_paginate/view_helpers.rb +95 -0
- data/doc/demo/vendor/plugins/will_paginate/test/array_pagination_test.rb +23 -0
- data/doc/demo/vendor/plugins/will_paginate/test/boot.rb +27 -0
- data/doc/demo/vendor/plugins/will_paginate/test/console +10 -0
- data/doc/demo/vendor/plugins/will_paginate/test/finder_test.rb +219 -0
- data/doc/demo/vendor/plugins/will_paginate/test/fixtures/admin.rb +3 -0
- data/doc/demo/vendor/plugins/will_paginate/test/fixtures/companies.yml +24 -0
- data/doc/demo/vendor/plugins/will_paginate/test/fixtures/company.rb +23 -0
- data/doc/demo/vendor/plugins/will_paginate/test/fixtures/developer.rb +11 -0
- data/doc/demo/vendor/plugins/will_paginate/test/fixtures/developers_projects.yml +13 -0
- data/doc/demo/vendor/plugins/will_paginate/test/fixtures/project.rb +4 -0
- data/doc/demo/vendor/plugins/will_paginate/test/fixtures/projects.yml +7 -0
- data/doc/demo/vendor/plugins/will_paginate/test/fixtures/replies.yml +20 -0
- data/doc/demo/vendor/plugins/will_paginate/test/fixtures/reply.rb +5 -0
- data/doc/demo/vendor/plugins/will_paginate/test/fixtures/schema.sql +44 -0
- data/doc/demo/vendor/plugins/will_paginate/test/fixtures/topic.rb +19 -0
- data/doc/demo/vendor/plugins/will_paginate/test/fixtures/topics.yml +30 -0
- data/doc/demo/vendor/plugins/will_paginate/test/fixtures/user.rb +2 -0
- data/doc/demo/vendor/plugins/will_paginate/test/fixtures/users.yml +35 -0
- data/doc/demo/vendor/plugins/will_paginate/test/helper.rb +42 -0
- data/doc/demo/vendor/plugins/will_paginate/test/lib/activerecord_test_connector.rb +64 -0
- data/doc/demo/vendor/plugins/will_paginate/test/lib/load_fixtures.rb +10 -0
- data/doc/demo/vendor/plugins/will_paginate/test/pagination_test.rb +136 -0
- data/doc/monit-example +22 -0
- data/init.rb +24 -0
- data/install.rb +18 -0
- data/lib/act_methods.rb +147 -0
- data/lib/acts_as_ferret.rb +584 -0
- data/lib/ar_mysql_auto_reconnect_patch.rb +41 -0
- data/lib/blank_slate.rb +53 -0
- data/lib/bulk_indexer.rb +38 -0
- data/lib/class_methods.rb +270 -0
- data/lib/ferret_extensions.rb +188 -0
- data/lib/ferret_find_methods.rb +141 -0
- data/lib/ferret_result.rb +53 -0
- data/lib/ferret_server.rb +238 -0
- data/lib/index.rb +99 -0
- data/lib/instance_methods.rb +171 -0
- data/lib/local_index.rb +205 -0
- data/lib/more_like_this.rb +217 -0
- data/lib/multi_index.rb +126 -0
- data/lib/rdig_adapter.rb +148 -0
- data/lib/remote_functions.rb +23 -0
- data/lib/remote_index.rb +54 -0
- data/lib/remote_multi_index.rb +20 -0
- data/lib/search_results.rb +50 -0
- data/lib/server_manager.rb +58 -0
- data/lib/unix_daemon.rb +64 -0
- data/lib/without_ar.rb +52 -0
- data/rakefile +141 -0
- data/recipes/aaf_recipes.rb +114 -0
- data/script/ferret_daemon +94 -0
- data/script/ferret_server +10 -0
- data/script/ferret_service +178 -0
- data/tasks/ferret.rake +22 -0
- metadata +258 -0
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
require File.dirname(__FILE__) + '/../../test_helper'
|
|
2
|
+
require 'admin/backend_controller'
|
|
3
|
+
|
|
4
|
+
# Re-raise errors caught by the controller.
|
|
5
|
+
class Admin::BackendController; def rescue_action(e) raise e end; end
|
|
6
|
+
|
|
7
|
+
class Admin::BackendControllerTest < Test::Unit::TestCase
|
|
8
|
+
def setup
|
|
9
|
+
@controller = Admin::BackendController.new
|
|
10
|
+
@request = ActionController::TestRequest.new
|
|
11
|
+
@response = ActionController::TestResponse.new
|
|
12
|
+
Content.destroy_all
|
|
13
|
+
Content.create(:title => 'my title', :description => 'a little bit of content')
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def teardown
|
|
17
|
+
Content.destroy_all
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def test_search
|
|
21
|
+
get :search
|
|
22
|
+
assert_response :success
|
|
23
|
+
assert_template 'search'
|
|
24
|
+
assert_nil assigns(:results)
|
|
25
|
+
|
|
26
|
+
post :search, :query => 'title'
|
|
27
|
+
assert_template 'search'
|
|
28
|
+
assert_equal 1, assigns(:results).size
|
|
29
|
+
|
|
30
|
+
post :search, :query => 'monkey'
|
|
31
|
+
assert_template 'search'
|
|
32
|
+
assert assigns(:results).empty?
|
|
33
|
+
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
require File.dirname(__FILE__) + '/../test_helper'
|
|
2
|
+
require 'contents_controller'
|
|
3
|
+
|
|
4
|
+
# Re-raise errors caught by the controller.
|
|
5
|
+
class ContentsController; def rescue_action(e) raise e end; end
|
|
6
|
+
|
|
7
|
+
class ContentsControllerTest < Test::Unit::TestCase
|
|
8
|
+
fixtures :contents
|
|
9
|
+
|
|
10
|
+
def setup
|
|
11
|
+
@controller = ContentsController.new
|
|
12
|
+
@request = ActionController::TestRequest.new
|
|
13
|
+
@response = ActionController::TestResponse.new
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def test_index
|
|
17
|
+
get :index
|
|
18
|
+
assert_response :success
|
|
19
|
+
assert_template 'index'
|
|
20
|
+
assert_not_nil assigns(:contents)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def test_show
|
|
24
|
+
get :show, :id => 1
|
|
25
|
+
|
|
26
|
+
assert_response :success
|
|
27
|
+
assert_template 'show'
|
|
28
|
+
|
|
29
|
+
assert_not_nil assigns(:content)
|
|
30
|
+
assert assigns(:content).valid?
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def test_new
|
|
34
|
+
get :new
|
|
35
|
+
|
|
36
|
+
assert_response :success
|
|
37
|
+
assert_template 'new'
|
|
38
|
+
|
|
39
|
+
assert_not_nil assigns(:content)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def test_create
|
|
43
|
+
num_contents = Content.count
|
|
44
|
+
|
|
45
|
+
post :create, :content => {}
|
|
46
|
+
|
|
47
|
+
assert_response :redirect
|
|
48
|
+
assert_redirected_to contents_url
|
|
49
|
+
|
|
50
|
+
assert_equal num_contents + 1, Content.count
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def test_edit
|
|
54
|
+
get :edit, :id => 1
|
|
55
|
+
|
|
56
|
+
assert_response :success
|
|
57
|
+
assert_template 'edit'
|
|
58
|
+
|
|
59
|
+
assert_not_nil assigns(:content)
|
|
60
|
+
assert assigns(:content).valid?
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def test_update
|
|
64
|
+
post :update, :id => 1
|
|
65
|
+
assert_response :redirect
|
|
66
|
+
assert_redirected_to :action => 'show', :id => 1
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def test_destroy
|
|
70
|
+
assert_not_nil Content.find(1)
|
|
71
|
+
|
|
72
|
+
post :destroy, :id => 1
|
|
73
|
+
assert_response :redirect
|
|
74
|
+
assert_redirected_to :action => 'list'
|
|
75
|
+
|
|
76
|
+
assert_raise(ActiveRecord::RecordNotFound) {
|
|
77
|
+
Content.find(1)
|
|
78
|
+
}
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
end
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
require File.dirname(__FILE__) + '/../test_helper'
|
|
2
|
+
require 'searches_controller'
|
|
3
|
+
|
|
4
|
+
# Re-raise errors caught by the controller.
|
|
5
|
+
class SearchesController; def rescue_action(e) raise e end; end
|
|
6
|
+
|
|
7
|
+
class SearchesControllerTest < Test::Unit::TestCase
|
|
8
|
+
fixtures :contents
|
|
9
|
+
|
|
10
|
+
def setup
|
|
11
|
+
@controller = SearchesController.new
|
|
12
|
+
@request = ActionController::TestRequest.new
|
|
13
|
+
@response = ActionController::TestResponse.new
|
|
14
|
+
ContentBase.rebuild_index
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def test_search
|
|
18
|
+
get :search
|
|
19
|
+
assert_template 'search'
|
|
20
|
+
assert_response :success
|
|
21
|
+
assert_nil assigns(:results)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def test_search
|
|
25
|
+
get :search, :q => 'title'
|
|
26
|
+
assert_template 'search'
|
|
27
|
+
assert_equal 1, assigns(:results).total_hits
|
|
28
|
+
assert_equal 1, assigns(:results).size
|
|
29
|
+
|
|
30
|
+
get :search, :q => 'monkey'
|
|
31
|
+
assert_template 'search'
|
|
32
|
+
assert assigns(:results).empty?
|
|
33
|
+
|
|
34
|
+
# check that model changes are picked up by the searcher (searchers have to
|
|
35
|
+
# be reopened to reflect changes done to the index)
|
|
36
|
+
# wait for the searcher to age a bit (it seems fs timestamp resolution is
|
|
37
|
+
# only 1 sec)
|
|
38
|
+
sleep 1
|
|
39
|
+
Content.create :title => 'another content object', :description => 'description goes hers'
|
|
40
|
+
get :search, :q => 'another'
|
|
41
|
+
assert_template 'search'
|
|
42
|
+
assert_equal 1, assigns(:results).total_hits
|
|
43
|
+
assert_equal 1, assigns(:results).size
|
|
44
|
+
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def test_pagination
|
|
48
|
+
Content.destroy_all
|
|
49
|
+
30.times do |i|
|
|
50
|
+
Content.create! :title => "title of Content #{i}", :description => "#{i}"
|
|
51
|
+
end
|
|
52
|
+
get :search, :q => 'title'
|
|
53
|
+
r = assigns(:results)
|
|
54
|
+
assert_equal 30, r.total_hits
|
|
55
|
+
assert_equal 10, r.size
|
|
56
|
+
assert_equal "title of Content 0", r.first.title
|
|
57
|
+
assert_equal "title of Content 9", r.last.title
|
|
58
|
+
assert_equal 1, r.current_page
|
|
59
|
+
assert_equal 3, r.page_count
|
|
60
|
+
|
|
61
|
+
get :search, :q => 'title', :page => 2
|
|
62
|
+
r = assigns(:results)
|
|
63
|
+
assert_equal 30, r.total_hits
|
|
64
|
+
assert_equal 10, r.size
|
|
65
|
+
assert_equal "title of Content 10", r.first.title
|
|
66
|
+
assert_equal "title of Content 19", r.last.title
|
|
67
|
+
assert_equal 2, r.current_page
|
|
68
|
+
assert_equal 3, r.page_count
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
end
|
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
require 'rubygems'
|
|
2
|
+
require 'benchmark'
|
|
3
|
+
require 'gruff'
|
|
4
|
+
|
|
5
|
+
# Simple smoke test for the DRb server
|
|
6
|
+
# usage:
|
|
7
|
+
#
|
|
8
|
+
# # start the DRb server
|
|
9
|
+
# script/ferret_server -e test start
|
|
10
|
+
#
|
|
11
|
+
# # run the script
|
|
12
|
+
# AAF_REMOTE=true script/runner -e test test/smoke/drb_smoke_test.rb
|
|
13
|
+
|
|
14
|
+
module DrbSmokeTest
|
|
15
|
+
|
|
16
|
+
RECORDS_PER_PROCESS = 100000
|
|
17
|
+
NUM_PROCESSES = 10 # should be an even number
|
|
18
|
+
NUM_DOCS = 50
|
|
19
|
+
NUM_TERMS = 600
|
|
20
|
+
START_TIME = Time.now
|
|
21
|
+
|
|
22
|
+
class Words
|
|
23
|
+
DICTIONARY = '/usr/share/dict/words'
|
|
24
|
+
def initialize
|
|
25
|
+
@words = []
|
|
26
|
+
File.open(DICTIONARY) do |file|
|
|
27
|
+
file.each_line do |word|
|
|
28
|
+
@words << word.strip unless word =~ /'/
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def to_s
|
|
34
|
+
"#{@words.size} words"
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def random_word
|
|
38
|
+
@words[rand(@words.size)]
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
puts "compiling sample documents..."
|
|
43
|
+
WORDS = Words.new
|
|
44
|
+
puts WORDS
|
|
45
|
+
DOCUMENTS = []
|
|
46
|
+
|
|
47
|
+
NUM_DOCS.times do
|
|
48
|
+
doc = ''
|
|
49
|
+
NUM_TERMS.times { doc << WORDS.random_word << ' ' }
|
|
50
|
+
DOCUMENTS << doc
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def self.random_document
|
|
54
|
+
DOCUMENTS[rand(DOCUMENTS.size)]
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
puts "built #{NUM_DOCS} documents with an avg. size of #{DOCUMENTS.join.size / NUM_DOCS} Bytes."
|
|
58
|
+
|
|
59
|
+
class Monitor
|
|
60
|
+
class << self
|
|
61
|
+
def count_connections
|
|
62
|
+
res = Content.connection.execute("show status where variable_name = 'Threads_connected'")
|
|
63
|
+
if res
|
|
64
|
+
res.fetch_row.last
|
|
65
|
+
else
|
|
66
|
+
"error getting connection count"
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
def writers_running?
|
|
70
|
+
Dir['*.finished'].size < (NUM_PROCESSES/2)
|
|
71
|
+
end
|
|
72
|
+
def running?
|
|
73
|
+
Dir['*.finished'].size < NUM_PROCESSES
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
class WorkerBase
|
|
79
|
+
def initialize(id)
|
|
80
|
+
@id = id
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# time since startup in msec
|
|
84
|
+
def get_time
|
|
85
|
+
((Time.now - START_TIME)*1000).to_i
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def log(data)
|
|
89
|
+
data << get_time
|
|
90
|
+
@logfile << data.join(',') << "\n"
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def log_finished
|
|
94
|
+
File.open("#{@id}.finished", 'w') do |f|
|
|
95
|
+
f << "finished at #{Time.now}\n"
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def clear_logs
|
|
100
|
+
FileUtils.rm_f "#{@id}.*"
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def run
|
|
104
|
+
File.open("#{self.class.prefix}_#{@id}.log",'w') do |f|
|
|
105
|
+
clear_logs
|
|
106
|
+
sleep 1 # allow other processes to get ready
|
|
107
|
+
@logfile = f
|
|
108
|
+
do_run
|
|
109
|
+
log_finished
|
|
110
|
+
puts "#{@id} finished"
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
class Writer < WorkerBase
|
|
117
|
+
def self.prefix; 'writer' end
|
|
118
|
+
def do_run
|
|
119
|
+
log_interval = RECORDS_PER_PROCESS / 100
|
|
120
|
+
RECORDS_PER_PROCESS.times do |i|
|
|
121
|
+
log create_record(i)
|
|
122
|
+
if i % log_interval == 0
|
|
123
|
+
# log progress
|
|
124
|
+
puts "#{@id}: #{i} records indexed"
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def create_record(i)
|
|
130
|
+
time = Benchmark.realtime do
|
|
131
|
+
Content.create! :title => "record #{@id} / #{i}", :description => DrbSmokeTest::random_document
|
|
132
|
+
end
|
|
133
|
+
[ time ]
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
class Searcher < WorkerBase
|
|
138
|
+
def self.prefix; 'searcher' end
|
|
139
|
+
def do_run
|
|
140
|
+
while Monitor::writers_running?
|
|
141
|
+
# search with concurrent writes
|
|
142
|
+
log do_search
|
|
143
|
+
end
|
|
144
|
+
t = Time.now
|
|
145
|
+
while (Time.now - t) < 2.minutes
|
|
146
|
+
# the writers have finished, now hammer the server with searches for another 5 minutes
|
|
147
|
+
log do_search
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
# run a search and log it's results.
|
|
152
|
+
# Search is done with a query consisting of the term 'findme'
|
|
153
|
+
# (which is guaranteed to yield 20 results) and a random term from
|
|
154
|
+
# the word list, ORed together
|
|
155
|
+
def do_search
|
|
156
|
+
result = nil
|
|
157
|
+
query = "findme OR #{WORDS.random_word}"
|
|
158
|
+
time = Benchmark.realtime do
|
|
159
|
+
result = Content.find_id_by_contents query
|
|
160
|
+
end
|
|
161
|
+
# time, no of hits
|
|
162
|
+
[ time, result.first, query ]
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
def self.run
|
|
167
|
+
@start = Time.now
|
|
168
|
+
|
|
169
|
+
NUM_PROCESSES.times do |i|
|
|
170
|
+
unless fork
|
|
171
|
+
@id = i
|
|
172
|
+
break
|
|
173
|
+
end
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
if @id
|
|
177
|
+
@id.even? ? Writer.new(@id).run : Searcher.new(@id).run
|
|
178
|
+
else
|
|
179
|
+
|
|
180
|
+
# create some records to search for
|
|
181
|
+
20.times do |i|
|
|
182
|
+
Content.create! :title => "to find #{i}", :description => ("findme #{i} " << random_document)
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
while Monitor::running?
|
|
186
|
+
puts "open connections: #{Monitor::count_connections}; time elapsed: #{Time.now - @start} seconds"
|
|
187
|
+
sleep 10
|
|
188
|
+
end
|
|
189
|
+
puts "doing the math now..."
|
|
190
|
+
DrbSmokeTest::Stats.new(DrbSmokeTest::Writer::prefix).run
|
|
191
|
+
DrbSmokeTest::Stats.new(DrbSmokeTest::Searcher::prefix).run
|
|
192
|
+
end
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
module Statistics
|
|
196
|
+
def odd?(value)
|
|
197
|
+
value % 2 == 1
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
def median(population)
|
|
201
|
+
if odd?(population.size)
|
|
202
|
+
population[population.size/2]
|
|
203
|
+
else
|
|
204
|
+
mean [ population[population.size/2-1], population[population.size/2] ]
|
|
205
|
+
end
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
def mean(population)
|
|
209
|
+
sum = population.inject(0) { |sum, v| sum + v }
|
|
210
|
+
sum / population.size.to_f
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
# variance and standard_deviation methods from
|
|
214
|
+
# http://warrenseen.com/blog/2006/03/13/how-to-calculate-standard-deviation/
|
|
215
|
+
def variance(population)
|
|
216
|
+
n = 0
|
|
217
|
+
mean = 0.0
|
|
218
|
+
s = 0.0
|
|
219
|
+
population.each { |x|
|
|
220
|
+
n = n + 1
|
|
221
|
+
delta = x - mean
|
|
222
|
+
mean = mean + (delta / n)
|
|
223
|
+
s = s + delta * (x - mean)
|
|
224
|
+
}
|
|
225
|
+
# if you want to calculate std deviation
|
|
226
|
+
# of a sample change this to "s / (n-1)"
|
|
227
|
+
return s / n
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
# calculate the standard deviation of a population
|
|
231
|
+
# accepts: an array, the population
|
|
232
|
+
# returns: the standard deviation
|
|
233
|
+
def standard_deviation(population)
|
|
234
|
+
Math.sqrt(variance(population))
|
|
235
|
+
rescue
|
|
236
|
+
puts "pop: #{population.inspect}"
|
|
237
|
+
end
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
class Stats
|
|
241
|
+
include Statistics
|
|
242
|
+
|
|
243
|
+
def initialize(prefix)
|
|
244
|
+
@prefix = prefix
|
|
245
|
+
@stats = []
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
def collect_stats
|
|
249
|
+
Dir["#{@prefix}_*.log"].each do |logfile|
|
|
250
|
+
puts logfile
|
|
251
|
+
File.open(logfile) do |f|
|
|
252
|
+
while line = f.gets
|
|
253
|
+
row = line.split(',')
|
|
254
|
+
row[row.size-1] = row.last.to_i
|
|
255
|
+
@stats << row
|
|
256
|
+
end
|
|
257
|
+
end
|
|
258
|
+
end
|
|
259
|
+
puts "#{@stats.size} lines read, now sorting..."
|
|
260
|
+
@stats.sort! { |row1, row2| row1.last <=> row2.last }
|
|
261
|
+
end
|
|
262
|
+
|
|
263
|
+
def with_segments(segment_count)
|
|
264
|
+
t0 = @stats.first.last.to_i
|
|
265
|
+
t1 = @stats.last.last.to_i
|
|
266
|
+
timespan = t1 - t0
|
|
267
|
+
puts "test run took: #{timespan/1000} seconds"
|
|
268
|
+
# we want to draw 1000 points, determine which timespan one point covers
|
|
269
|
+
segment_length = timespan / segment_count
|
|
270
|
+
t = 0
|
|
271
|
+
i = 0
|
|
272
|
+
while t <= t1
|
|
273
|
+
t += segment_length
|
|
274
|
+
segment_stats = []
|
|
275
|
+
while @stats.any? && @stats.first.last.to_i < t
|
|
276
|
+
segment_stats << @stats.shift
|
|
277
|
+
end
|
|
278
|
+
yield segment_stats unless segment_stats.empty?
|
|
279
|
+
end
|
|
280
|
+
end
|
|
281
|
+
|
|
282
|
+
def run
|
|
283
|
+
collect_stats
|
|
284
|
+
segments = []
|
|
285
|
+
with_segments(500) do |segment_stats|
|
|
286
|
+
segments << process_segment(segment_stats)
|
|
287
|
+
end
|
|
288
|
+
|
|
289
|
+
chart("#{@prefix} mean", "#{@prefix.downcase}_mean") do |g|
|
|
290
|
+
g.data :mean, segments.map{ |row| row[0] }
|
|
291
|
+
g.data :stddev, segments.map{ |row| row[1] }
|
|
292
|
+
end
|
|
293
|
+
chart("#{@prefix} median", "#{@prefix.downcase}_median") do |g|
|
|
294
|
+
g.data :median, segments.map{ |row| row[2] }
|
|
295
|
+
end
|
|
296
|
+
end
|
|
297
|
+
|
|
298
|
+
def process_segment(segment)
|
|
299
|
+
times = segment.map{|row|row.first.to_i * 1000}
|
|
300
|
+
[mean(times), standard_deviation(times), median(times), segment.size]
|
|
301
|
+
end
|
|
302
|
+
|
|
303
|
+
def chart(title, fname)
|
|
304
|
+
g = Gruff::Line.new do |g|
|
|
305
|
+
g.title = title
|
|
306
|
+
g.theme = {
|
|
307
|
+
:background_colors => ["#e6e6e6", "#e6e6e6"],
|
|
308
|
+
:colors => ["#ff43a7", '#666666', 'black', 'white', 'grey'],
|
|
309
|
+
:marker_color => "white"
|
|
310
|
+
}
|
|
311
|
+
end
|
|
312
|
+
yield g
|
|
313
|
+
g.write "#{fname}.png"
|
|
314
|
+
end
|
|
315
|
+
end
|
|
316
|
+
|
|
317
|
+
end
|
|
318
|
+
|
|
319
|
+
|
|
320
|
+
DrbSmokeTest::run
|
|
321
|
+
|