Skip to content

Commit

Permalink
Initial commit of master and slaves read/write split
Browse files Browse the repository at this point in the history
  • Loading branch information
Durran Jordan and Les Hill authored and durran committed Feb 5, 2010
1 parent 0805b63 commit 3da5a74
Show file tree
Hide file tree
Showing 14 changed files with 566 additions and 15 deletions.
1 change: 1 addition & 0 deletions lib/mongoid.rb
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
require "mongoid/associations/options"
require "mongoid/attributes"
require "mongoid/callbacks"
require "mongoid/collection"
require "mongoid/commands"
require "mongoid/config"
require "mongoid/contexts"
Expand Down
21 changes: 21 additions & 0 deletions lib/mongoid/collection.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# encoding: utf-8
require "mongoid/collections/cyclic_iterator"
require "mongoid/collections/reader"
require "mongoid/collections/writer"

module Mongoid #:nodoc
class Collection

# Initialize a new Mongoid::Collection, setting up the master, slave, and
# name attributes. Masters will be used for writes, slaves for reads.
#
# Example:
#
# <tt>Mongoid::Collection.new(masters, slaves, "test")</tt>
def initialize(name)
# Get all the master db -> Mongoid.master
# Get all the slave dbs -> Mongoid.slaves
@name = name
end
end
end
34 changes: 34 additions & 0 deletions lib/mongoid/collections/cyclic_iterator.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# encoding: utf-8
module Mongoid #:nodoc:
module Collections #:nodoc:
class CyclicIterator

attr_reader :counter

# Performs iteration over an array, if the array gets to the end then loop
# back to the first.
#
# Example:
#
# <tt>CyclicIterator.new([ first, second ])</tt>
def initialize(array)
@array, @counter = array, -1
end

# Get the next element in the array. If the element is the last in the
# array then return the first.
#
# Example:
#
# <tt>iterator.next</tt>
#
# Returns:
#
# The next element in the array.
def next
(@counter == @array.size - 1) ? @counter = 0 : @counter = @counter + 1
@array[@counter]
end
end
end
end
38 changes: 38 additions & 0 deletions lib/mongoid/collections/reader.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# encoding: utf-8
module Mongoid #:nodoc:
module Collections #:nodoc:
class Reader

attr_reader :iterator

delegate \
:count,
:distinct,
:find,
:find_one,
:group,
:index_information,
:map_reduce,
:mapreduce,
:options,
:size, :to => :collection

# Create the new database reader. Will create a collection from the
# slave databases and cycle through them on each read.
#
# Example:
#
# <tt>Reader.new(slaves, "mongoid_people")</tt>
def initialize(slaves, name)
@iterator = CyclicIterator.new(
slaves.collect { |db| db.collection(name) }
)
end

protected
def collection
@iterator.next
end
end
end
end
30 changes: 30 additions & 0 deletions lib/mongoid/collections/writer.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# encoding: utf-8
module Mongoid #:nodoc:
module Collections #:nodoc:
class Writer
attr_reader :collection

delegate \
:<<,
:create_index,
:drop,
:drop_index,
:drop_indexes,
:insert,
:remove,
:rename,
:save,
:update, :to => :collection

# Create the new database writer. Will create a collection from the
# master database.
#
# Example:
#
# <tt>Writer.new(master, "mongoid_people")</tt>
def initialize(master_db, name)
@collection = master_db.collection(name)
end
end
end
end
4 changes: 1 addition & 3 deletions lib/mongoid/config.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,13 @@ class Config #:nodoc
attr_accessor \
:allow_dynamic_fields,
:persist_in_safe_mode,
:raise_not_found_error,
:temp_collection_size
:raise_not_found_error

# Defaults the configuration options to true.
def initialize
@allow_dynamic_fields = true
@persist_in_safe_mode = true
@raise_not_found_error = true
@temp_collection_size = 1048576
end

# Sets the Mongo::DB to be used.
Expand Down
37 changes: 34 additions & 3 deletions lib/mongoid/criteria.rb
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,18 @@ def self.translate(*args)
end

protected
# Determines the context to be used for this criteria.
# Determines the context to be used for this criteria. If the class is an
# embedded document, then thw context will be the array in the has_many
# association it is in. If the class is a root, then the database itself
# will be the context.
#
# Example:
#
# <tt>criteria#determine_context</tt>
#
# Returns:
#
# A enumerable or mongo context.
def determine_context
if @klass.embedded
return Contexts::Enumerable.new(@selector, @options, @documents)
Expand All @@ -233,6 +244,12 @@ def determine_context
# Filters the unused options out of the options +Hash+. Currently this
# takes into account the "page" and "per_page" options that would be passed
# in if using will_paginate.
#
# Example:
#
# Given a criteria with a selector of { :page => 1, :per_page => 40 }
#
# <tt>criteria.filter_options</tt> # selector: { :skip => 0, :limit => 40 }
def filter_options
page_num = @options.delete(:page)
per_page_num = @options.delete(:per_page)
Expand All @@ -242,19 +259,33 @@ def filter_options
end
end

# Return the entries of the other criteria or the object.
# Return the entries of the other criteria or the object. Used for
# comparing criteria or an enumerable.
def comparable(other)
other.is_a?(Criteria) ? other.entries : other
end

# Update the selector setting the operator on the value for each key in the
# supplied attributes +Hash+.
#
# Example:
#
# <tt>criteria.update_selector({ :field => "value" }, "$in")</tt>
def update_selector(attributes, operator)
attributes.each { |key, value| @selector[key] = { operator => value } }; self
end

class << self
# Return a criteria or single document based on an id search.
# Create a criteria or single document based on an id search. Will handle
# if a single id has been passed or mulitple ids.
#
# Example:
#
# Criteria.id_criteria(Person, [1, 2, 3])
#
# Returns:
#
# The single or multiple documents.
def id_criteria(klass, params)
criteria = new(klass).id(params)
result = params.is_a?(String) ? criteria.one : criteria.entries
Expand Down
3 changes: 3 additions & 0 deletions lib/mongoid/criterion/union.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ def identifiers
# Perform a union of 2 criteria and return the new criteria. The first
# pass executes both sides and merges the collections together.
#
# Note this operation can we extremely memory instensive for large
# collections - use with caution.
#
# Example:
#
# <tt>criteria.or(other_criteria)</tt>
Expand Down
11 changes: 10 additions & 1 deletion spec/spec_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,16 @@
require "spec"

Mongoid.configure do |config|
config.database = Mongo::Connection.new.db("mongoid_test")
name = "mongoid_test"
config.database = Mongo::Connection.new.db(name)
# config.masters = [
# Mongo::Connection.new(host, port).db(name),
# Mongo::Connection.new(host, port).db(name)
# ]
# config.slaves = [
# Mongo::Connection.new(host, port, :slave_ok => true).db(name),
# Mongo::Connection.new(host, port, :slave_ok => true).db(name)
# ]
end

Dir[File.join(MODELS, "*.rb")].sort.each {|file| require File.basename(file) }
Expand Down
34 changes: 34 additions & 0 deletions spec/unit/mongoid/collection_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
require "spec_helper"

describe Mongoid::Collection do

let(:master) do
stub.quacks_like(Mongo::DB.allocate)
end

let(:slave_one) do
stub.quacks_like(Mongo::DB.allocate)
end

let(:slave_two) do
stub.quacks_like(Mongo::DB.allocate)
end

let(:slaves) do
[ slave_one, slave_two ]
end

describe "#initialize" do

let(:collection) do
Mongoid::Collection.new(master, slaves, "mongoid_test")
end

it "sets the master db"

it "sets the slave dbs"

it "sets the name"
end

end
75 changes: 75 additions & 0 deletions spec/unit/mongoid/collections/cyclic_iterator_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
require "spec_helper"

describe Mongoid::Collections::CyclicIterator do

before do
@first = stub
@second = stub
@third = stub
@fourth = stub
end

let(:array) do
[ @first, @second, @third, @fourth ]
end

describe "#initialize" do

let(:iterator) do
Mongoid::Collections::CyclicIterator.new(array)
end

it "defaults the counter to -1" do
iterator.counter.should == -1
end
end

describe "#next" do

context "when the iterator has just been created" do

let(:iterator) do
Mongoid::Collections::CyclicIterator.new(array)
end

it "returns the first element" do
iterator.next.should == @first
end
end

context "when the iterator is in the middle" do

let(:iterator) do
Mongoid::Collections::CyclicIterator.new(array)
end

before do
2.times { iterator.next }
end

it "returns the next element given the index" do
iterator.next.should == @third
end
end

context "when the iterator is on the last element" do

let(:iterator) do
Mongoid::Collections::CyclicIterator.new(array)
end

before do
4.times { iterator.next }
end

it "returns the first element" do
iterator.next.should == @first
end

it "resets the counter" do
iterator.next
iterator.counter.should == 0
end
end
end
end
Loading

0 comments on commit 3da5a74

Please sign in to comment.