nightcrawler 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -2,3 +2,4 @@
2
2
  .bundle
3
3
  Gemfile.lock
4
4
  pkg/*
5
+ *.db
@@ -0,0 +1,20 @@
1
+ ## each instance controls the complete set of similar shards
2
+ #class Mosaic
3
+
4
+ ## a parent namespace for all our sharded models
5
+ #module ShardPool; end
6
+
7
+ ## name should be unique across mosaics
8
+ #def initialize(name, keys_configs, &block=nil)
9
+ #@name = name
10
+ #@keys_configs = keys_configs
11
+ #@block = block
12
+ #@shards = {}
13
+ #@keys_configs.each do |k,v|
14
+ #@shard_klass[k] =
15
+ #end
16
+
17
+
18
+ #end
19
+
20
+
@@ -1,3 +1,3 @@
1
1
  module Nightcrawler
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.2"
3
3
  end
@@ -0,0 +1,101 @@
1
+ #require 'spec_helper'
2
+
3
+ #describe Mosaic do
4
+ #before(:each) do
5
+ #@builder = ShardBuilder.new(3)
6
+ #shard_configs = (1..3).inject({}) {|h,i| h.merge "shard#{i}".to_sym => @builder.config(i)}
7
+ #Mosaic.new(shard_configs) do
8
+ #class Parent < Shard; end
9
+ #class Child < Shard; end
10
+ #end
11
+ #end
12
+
13
+ #it "should provide the correct model for the given shard" do
14
+ #(1..3).each do |i|
15
+ #Parent.shard("shard#{i}".to_sym).first.name.split(']')[0].should== "[shard ##{i}"
16
+ #end
17
+ #end
18
+
19
+ #it "should provide the correct model for the given shard" do
20
+ #Mosaic.shards.each do |shard|
21
+ #shard::Parent.first.name.split(']')[0].should== "[shard ##{shard.key}"
22
+ #end
23
+ #end
24
+ #end
25
+
26
+ #class Comment < ActiveRecord::Base
27
+ #include Nightcrawler::Sharding
28
+ #establish_connection :adapter => "sqlite3", :database => File.expand_path(File.join(File.dirname(__FILE__), "db", "master.db"))
29
+
30
+ #validates_presence_of :shard_key
31
+
32
+ #shard_by :shard_key
33
+
34
+ #def self.find_shard(value)
35
+ #"shard#{value}".to_sym
36
+ #end
37
+
38
+ #def self.shard_for(key)
39
+ #$shards[key]
40
+ #end
41
+
42
+ #end
43
+
44
+
45
+ #@shard_builder = TestShardBuilder.new(4)
46
+
47
+ #before(:each) do
48
+ #@shard_builder.build
49
+ #end
50
+
51
+ #after(:each) do
52
+ #@shard_builder.destroy
53
+ #end
54
+
55
+
56
+
57
+ #it "should do something" do
58
+ #Comment.shard(:shard1).should == CommentShard1
59
+ #end
60
+ #it "should create second shard" do
61
+ #Comment.shard(:shard2).should == CommentShard2
62
+ #end
63
+
64
+ #describe "creating a comment" do
65
+ #before(:all) do
66
+ #@comment = Comment.shard(:shard1).create!(:shard_key => 1, :comment => "comment number 1")
67
+ #end
68
+ #after(:all) do
69
+ #@comment.destroy
70
+ #end
71
+ #it "should exist on the first shard" do
72
+ #Comment.shard(:shard1).where(:comment => "comment number 1").first.should == @comment
73
+ #end
74
+ #it "should not exist on the second shard" do
75
+ #Comment.shard(:shard2).where(:comment => "comment number 1").should be_empty
76
+ #end
77
+ #end
78
+
79
+ #describe "search for a comment" do
80
+ #before(:all) do
81
+ #@comment1 = Comment.shard(:shard1).create!(:shard_key => 1, :comment => "blah")
82
+ #@comment2 = Comment.shard(:shard2).create!(:shard_key => 2, :comment => "blah")
83
+ #end
84
+ #after(:all) do
85
+ #@comment1.destroy rescue nil
86
+ #@comment2.destroy rescue nil
87
+ #end
88
+ #it "should lookup shard based on relation" do
89
+ #Comment.where(:shard_key => 1).where(:comment => "blah").size.should == 1
90
+ #Comment.where(:shard_key => 1).where(:comment => "blah").first.should be_a CommentShard1
91
+ #Comment.where(:shard_key => 2).size.should == 1
92
+ #Comment.where(:shard_key => 2).first.should be_a Comment
93
+ #Comment.where(:shard_key => 2).first.should be_a CommentShard2
94
+ #end
95
+
96
+ #it "should not do blind relation" do
97
+ #lambda { Comment.where(:comment => "blah").to_a }.should raise_exception
98
+ #end
99
+ #end
100
+ #end
101
+
@@ -0,0 +1,88 @@
1
+ require 'spec_helper'
2
+ require 'active_record'
3
+
4
+ # ActiveRecord classes do not like to be inside anonymous modules-- if you want to anonymize, then you'll need a nested module!
5
+
6
+
7
+ describe ShardBuilder do
8
+ context "testing the shard builder" do
9
+
10
+ it "should raze the db dir as expected" do
11
+ builder = ShardBuilder.new
12
+ builder.raze
13
+ Dir.entries(File.expand_path("../db", __FILE__)).length.should == 2
14
+ FileUtils.touch File.expand_path("../db/blahblah", __FILE__)
15
+ FileUtils.touch File.expand_path("../db/yo.db", __FILE__)
16
+ Dir.entries(File.expand_path("../db", __FILE__)).length.should == 4
17
+ builder.raze
18
+ Dir.entries(File.expand_path("../db", __FILE__)).length.should == 2
19
+ end
20
+
21
+ it "should be able to connect to a single shard no problem" do
22
+ builder = ShardBuilder.new(1,3)
23
+ ActiveRecord::Base.establish_connection(builder.config(1))
24
+ module A
25
+ class Parent < ActiveRecord::Base; end
26
+ end
27
+ A::Parent.all.length.should == 3
28
+ A::Parent.all.each do |p|
29
+ p.name.should match(/^\[shard #1\]/)
30
+ end
31
+ end
32
+
33
+ # unfortunately this seems to require setting the table name!
34
+ it "should be able to leverage sandwich classes to hold the connections and still have relationships on a single shard" do
35
+ builder = ShardBuilder.new(1,3,5)
36
+ module B
37
+ class Shard < ActiveRecord::Base; end
38
+ class Parent < Shard; set_table_name "parents"; has_many :children end
39
+ class Child < Shard; set_table_name "children"; end
40
+ end
41
+ B::Shard.establish_connection(builder.config(1))
42
+ B::Parent.all.length.should == 3
43
+ B::Parent.all.each do |p|
44
+ p.name.should match(/^\[shard #1\]/)
45
+ p.children.length.should == 5
46
+ p.children.each do |c|
47
+ c.name.should match(/^\[shard #1\]/)
48
+ end
49
+ end
50
+ end
51
+
52
+ # unfortunately this seems to require setting the table name!
53
+ it "should be able to have relationships in each shard" do
54
+ builder = ShardBuilder.new(2,3,5)
55
+ module C1
56
+ class Shard < ActiveRecord::Base; end
57
+ class Parent < Shard; set_table_name "parents"; has_many :children end
58
+ class Child < Shard; set_table_name "children"; end
59
+ end
60
+ module C2
61
+ class Shard < ActiveRecord::Base; end
62
+ class Parent < Shard; set_table_name "parents"; has_many :children end
63
+ class Child < Shard; set_table_name "children"; end
64
+ end
65
+ C1::Shard.establish_connection(builder.config(1))
66
+ C2::Shard.establish_connection(builder.config(2))
67
+ C1::Parent.all.length.should == 3
68
+ C1::Parent.all.each do |p|
69
+ p.name.should match(/^\[shard #1\]/)
70
+ p.children.length.should == 5
71
+ p.children.each do |c|
72
+ c.name.should match(/^\[shard #1\]/)
73
+ end
74
+ end
75
+ C2::Parent.all.length.should == 3
76
+ C2::Parent.all.each do |p|
77
+ p.name.should match(/^\[shard #2\]/)
78
+ p.children.length.should == 5
79
+ p.children.each do |c|
80
+ c.name.should match(/^\[shard #2\]/)
81
+ end
82
+ end
83
+ end
84
+
85
+ end
86
+ end
87
+
88
+
@@ -0,0 +1,47 @@
1
+ require 'spec_helper'
2
+ require 'active_record'
3
+
4
+ # a utility class used only for tests that builds out a number of shards with parent & child tables prepopulated with some test data
5
+ class ShardBuilder
6
+ class Child < ActiveRecord::Base; end;
7
+ class Parent < ActiveRecord::Base; end;
8
+
9
+ def initialize(shard_count=3, parent_count=3, child_count=5)
10
+ @shard_count = shard_count
11
+ @parent_count = parent_count
12
+ @child_count = child_count
13
+ raze
14
+ build
15
+ end
16
+
17
+ def build
18
+ (1..@shard_count).each do |i|
19
+ base = ActiveRecord::Base
20
+ base.establish_connection(config(i))
21
+ base.connection.create_table "children" do |t|
22
+ t.integer :parent_id
23
+ t.string :name
24
+ end
25
+ base.connection.create_table "parents" do |t|
26
+ t.integer :id
27
+ t.string :name
28
+ end
29
+ (1..@parent_count).each do |j|
30
+ (1..@child_count).each do |k|
31
+ Child.create :parent_id=>j, :name=>"[shard ##{i}] child(##{k}) for parent(##{j})"
32
+ end
33
+ Parent.create :name=>"[shard ##{i}] parent(#{j})"
34
+ end
35
+ base.remove_connection(base)
36
+ end
37
+ end
38
+
39
+ def raze
40
+ FileUtils.rm_rf File.expand_path("../../db", __FILE__)
41
+ FileUtils.mkdir_p File.expand_path("../../db", __FILE__)
42
+ end
43
+
44
+ def config(shard_index)
45
+ {:adapter => "sqlite3", :database => File.expand_path("../../db/shard#{shard_index}.db", __FILE__)}
46
+ end
47
+ end
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: nightcrawler
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.0.1
5
+ version: 0.0.2
6
6
  platform: ruby
7
7
  authors:
8
8
  - Joshua Lane, Michael Prior
@@ -10,7 +10,8 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2011-05-02 00:00:00 Z
13
+ date: 2011-05-04 00:00:00 -04:00
14
+ default_executable:
14
15
  dependencies:
15
16
  - !ruby/object:Gem::Dependency
16
17
  name: rspec
@@ -108,13 +109,18 @@ files:
108
109
  - lib/nightcrawler.rb
109
110
  - lib/nightcrawler/manager.rb
110
111
  - lib/nightcrawler/migration.rb
112
+ - lib/nightcrawler/mosaic.rb
111
113
  - lib/nightcrawler/relation.rb
112
114
  - lib/nightcrawler/shard.rb
113
115
  - lib/nightcrawler/shard_descriptor.rb
114
116
  - lib/nightcrawler/version.rb
115
117
  - nightcrawler.gemspec
116
118
  - spec/manager_spec.rb
119
+ - spec/mosaic_spec.rb
120
+ - spec/shard_builder_spec.rb
117
121
  - spec/spec_helper.rb
122
+ - spec/support/shard_builder.rb
123
+ has_rdoc: true
118
124
  homepage: ""
119
125
  licenses: []
120
126
 
@@ -138,7 +144,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
138
144
  requirements: []
139
145
 
140
146
  rubyforge_project: nightcrawler
141
- rubygems_version: 1.7.2
147
+ rubygems_version: 1.6.2
142
148
  signing_key:
143
149
  specification_version: 3
144
150
  summary: Minimal sharding solution for AR