Browse files

add "bin/batsd delete <statistic>" command

  • Loading branch information...
1 parent 417856d commit a67e23ef6ada13486f74ae0fd35588ea7338d3e1 @groe groe committed Nov 21, 2012
Showing with 93 additions and 0 deletions.
  1. +10 −0 bin/batsd
  2. +1 −0 lib/batsd.rb
  3. +34 −0 lib/batsd/deleter.rb
  4. +24 −0 lib/batsd/diskstore.rb
  5. +12 −0 lib/batsd/redis.rb
  6. +12 −0 test/unit/diskstore_test.rb
View
10 bin/batsd
@@ -69,6 +69,16 @@ begin
ms: Batsd::Handler::Timer.new(config)
}
Batsd::Receiver::Daemon.new(handlers, config).run
+ when :delete
+ statistic = ARGV[1]
+ if !statistic.nil? && !statistic.empty?
+ @deleter = Batsd::Deleter.new(config)
+ @deleter.delete(statistic)
+ puts "Deleted \"#{statistic}\"."
+ else
+ puts "Need to specify a statistic."
+ exit 1
+ end
else
puts "I don't know how to #{command}."
exit 1
View
1 lib/batsd.rb
@@ -12,6 +12,7 @@
require 'batsd/statistics'
require 'batsd/truncator'
+require 'batsd/deleter'
require 'batsd/handler'
require 'batsd/handlers/gauge'
require 'batsd/handlers/counter'
View
34 lib/batsd/deleter.rb
@@ -0,0 +1,34 @@
+module Batsd
+ #
+ # Handle truncation for redis zsets and files written to disk
+ #
+ class Deleter
+
+ # Create a new truncator
+ #
+ # * Establish the diskstore that will be used
+ # * Establish the redis connection that will be needed
+ #
+ def initialize(options={})
+ @options = options
+ @redis = Batsd::Redis.new(options )
+ @diskstore = Batsd::Diskstore.new(options[:root])
+ end
+
+ def delete(statistic)
+ retentions = @options[:retentions].keys
+
+ # first retention
+ retentions.shift
+ @redis.clear_key(statistic)
+ @redis.remove_datapoint(statistic)
+
+ # other retentions
+ retentions.each do |retention|
+ key = "#{statistic}:#{retention}"
+ @diskstore.delete(@diskstore.build_filename(key), :delete_empty_dirs => true)
+ end
+ end
+
+ end
+end
View
24 lib/batsd/diskstore.rb
@@ -96,5 +96,29 @@ def truncate(filename, since)
FileUtils.rm("#{filename}tmp") rescue nil
end
+ # Deletes a file, if it exists.
+ # If :delete_empty_dirs is true, empty directories will be deleted too.
+ #
+ def delete(filename, options={})
+ if File.exists? filename
+ FileUtils.rm(filename)
+ end
+
+ if options[:delete_empty_dirs]
+ p = filename
+ begin
+ 2.times do
+ p = File.dirname(p)
+ Dir.rmdir(p) rescue break # only delete if dir is empty, else break
+ end
+ rescue => e
+ puts "Encountered an error trying to remove empty directory #{p}: #{e.class}"
+ end
+ end
+ rescue Errno::ENOENT => e
+ puts "Encountered an ENOENT error trying to delete #{filename}: #{e}" if ENV["VVERBOSE"]
+ rescue Exception => e
+ puts "Encountered an error trying to delete #{filename}: #{e.class}"
+ end
end
end
View
12 lib/batsd/redis.rb
@@ -81,6 +81,11 @@ def get_and_clear_key(key)
end.first
end
end
+
+ # Deletes the given key
+ def clear_key(key)
+ @redis.del(key)
+ end
# Create an array out of a string of values delimited by <X>
def extract_values_from_string(key)
@@ -137,5 +142,12 @@ def add_datapoint(key)
@redis.sadd "datapoints", key
end
+ # Stores a reference to the datapoint in
+ # the 'datapoints' set
+ #
+ def remove_datapoint(key)
+ @redis.srem "datapoints", key
+ end
+
end
end
View
12 test/unit/diskstore_test.rb
@@ -45,5 +45,17 @@ def test_truncate_cleans_up_file
assert_equal 26, @diskstore.read(@statistic, now.to_s, (now + 50).to_s).length
end
+ def test_delete_unlinks_file
+ @diskstore.delete(@diskstore.build_filename(@statistic))
+ assert_equal false, File.exists?(@diskstore.build_filename(@statistic))
+ # parent directory still exists
+ assert_equal true, File.exists?(File.dirname(@diskstore.build_filename(@statistic)))
+ # delete empty parents
+ @diskstore.delete(@diskstore.build_filename(@statistic), :delete_empty_dirs => true)
+ # now both parent directories are gone too
+ assert_equal false, File.exists?(File.dirname(@diskstore.build_filename(@statistic)))
+ assert_equal false, File.exists?(File.dirname(File.dirname(@diskstore.build_filename(@statistic))))
+ end
+
end

0 comments on commit a67e23e

Please sign in to comment.