require 'thread' require 'mongoid/collection_proxy' # # Proxy that enables runtime swapping of a MongoDB database, as it # appears to be cached at several points within Mongoid. # # This proxy is generated by the ConnectionProxy when asked for a # specific database. # class DatabaseProxy # # Semaphore for preventing badness when multithreading. # @mutex = Mutex.new # # All connections that we know about, and then the databases tied to # them get stored in here. # @pool = Hash.new # # Accessor for class-level instance variable that holds all the # connection-database pairs that we know about, so that we can # switch all of them globally. # def DatabaseProxy.pool @pool end # # Global mutex... for great thread safety! # def DatabaseProxy.mutex @mutex end # # Set our default connection and name. # def initialize(connection, name) @connection = connection switch(name) end # # Convenience method for synchronizing threads. # def synchronize(&block) DatabaseProxy.mutex.synchronize(&block) end # # Switch to a different database on the same connection. # def switch(name) synchronize do # Connect to the cached database if available. pool = (DatabaseProxy.pool[@connection] ||= {}) database = (pool[name] || (pool[name] = @connection.db(name))) # Set the default if we haven't, and away we go (for this # thread only). @default ||= database Thread.current[:mongo_database] = database end end # # Resets back to the default database connections. # def reset! synchronize { Thread.current[:mongo_database] = nil } end # # Returns the raw Mongo::DB object. # def target synchronize { Thread.current[:mongo_database] || @default } end # # Create a proxied collection. # def create_collection(name, opts) CollectionProxy.new(self, name, opts) end # # Proxy methods to the correct database. # def method_missing(*args, &block) target.send(*args, &block) end end