lib/gitmodel.rb in gitmodel-0.0.4 vs lib/gitmodel.rb in gitmodel-0.0.5
- old
+ new
@@ -1,14 +1,17 @@
+# coding: UTF-8
+
require 'rubygems'
require 'bundler/setup'
require 'active_model'
require 'active_support/all' # TODO we don't really want all here, clean this up
require 'grit'
-require 'yajl'
require 'lockfile'
+require 'memcache'
require 'pp'
+require 'yajl'
$:.unshift(File.dirname(__FILE__))
require 'gitmodel/errors'
require 'gitmodel/index'
require 'gitmodel/persistable'
@@ -30,10 +33,13 @@
self.logger.level = ::Logger::WARN
mattr_accessor :git_user_name
mattr_accessor :git_user_email
+ mattr_accessor :memcache_servers
+ mattr_accessor :memcache_namespace
+
def self.repo
@@repo = Grit::Repo.new(GitModel.db_root)
end
# Create the database defined in db_root. Raises an exception if it exists.
@@ -54,30 +60,66 @@
logger.info "Deleting database #{db_root}!!"
FileUtils.rm_rf db_root
create_db!
end
- def self.last_commit(branch = nil)
- branch ||= default_branch
- # PERFORMANCE Cache this somewhere and update it on commit?
- # (Need separate instance per branch)
-
- return nil unless repo.commits(branch).any?
-
- # We should be able to use just repo.commits(branch).first here but
- # this is a workaround for this bug:
- # http://github.com/mojombo/grit/issues/issue/38
- GitModel.repo.commits("#{branch}^..#{branch}").first || GitModel.repo.commits(branch).first
+ def self.last_commit(branch)
+ cache(branch, 'last-commit') do
+ unless repo.commits(branch).any?
+ nil
+ else
+ # We should be able to use just repo.commits(branch).first here but
+ # this is a workaround for this bug:
+ # http://github.com/mojombo/grit/issues/issue/38
+ GitModel.repo.commits("#{branch}^..#{branch}").first || GitModel.repo.commits(branch).first
+ end
+ end
end
- def self.current_tree(branch = nil)
+ def self.current_tree(branch)
c = last_commit(branch)
c ? c.tree : nil
end
- def self.index!
- dirs = (GitModel.current_tree).trees
+ def self.index!(branch)
+ dirs = (GitModel.current_tree(branch)).trees
dirs.each do |dir|
- dir.name.classify.constantize.index!
+ dir.name.classify.constantize.index!(branch)
end
+ end
+
+ # If we're using memcached (i.e. the memcache_servers setting is not nil) and
+ # the key exists in memcached, it's value will be returned and the block will
+ # not be run. If key does not exist in memcached, block will be executed,
+ # it's value stored in memcached under key, and value will be returned.
+ #
+ # There's no need to sweep the cache because the SHA of the latest Git commit
+ # is appended to the key, so any database change invalidates all cached
+ # objects.
+ def self.cache(branch, key, &block)
+ key = "#{key}-#{head_sha(branch)}"
+ value = nil
+ if memcache_servers
+ @@memcache ||= MemCache.new memcache_servers, :namespace => "#{File.basename(db_root)}-#{memcache_namespace}"
+ value = @@memcache.get(key)
+ if value.nil?
+ logger.info("✗ memcache MISS for key #{key}")
+ value = yield
+ @@memcache.set(key, value)
+ else
+ logger.info("✔ memcache HIT for key #{key}")
+ end
+ else
+ logger.debug("No memcache servers defined, not checking cache for key #{key}")
+ value = yield
+ end
+ value
+ end
+
+ private
+
+ # A more efficient way to get the SHA of the HEAD of the given branch
+ def self.head_sha(branch_name)
+ ref = File.join(repo.git.git_dir, "refs/heads/#{branch_name}")
+ File.exist?(ref) ? File.read(ref).chomp : nil
end
end