Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Batch Rename Keys

Tags:

redis

I have a rather large database (5 dbs of about a million keys each), and each key has the environment namespace in it. For example: "datamine::production::crosswalk==foobar"

I need to sync my development environment with this data copied from the production RDB snapshot.

So what I'm trying to do is batch rename every key, changing the namespace from datamine::production to datamine::development. Is there a good, way to achieve this?

What I've tried so far

  • redis-cli command of keys "datamine::production*", piped into sed, then back to redis-cli. This takes forever, and bombs for some reason on many keys (combining several in the same line, sporadically). I'd prefer a better option.

  • Perl search/replace on the .rdb file. My local redis-server flat refuses to load the modified RDB.

like image 754
Excalibur Avatar asked May 22 '26 18:05

Excalibur


1 Answers

The solution:

Ok, here's the script I wrote to solve this problem. It requires the "Redis" gem. Hopefully someone else finds this useful...

#!/usr/bin/env ruby

# A script to translate the current redis database into a namespace for another environment
# GWI's Redis keys are namespaced as "datamine::production", "datamine::development", etc.
# This script connects to redis and translates these key names in-place.
#
# This script does not use Rails, but needs the "redis" gem available
require 'Benchmark'
require 'Redis'

FROM_NAMESPACE = "production"
TO_NAMESPACE = "development"
NAMESPACE_PREFIX = "datamine::"
REDIS_SERVER = "localhost"
REDIS_PORT   = "6379"
REDIS_DBS = [0,1,2,3,4,5]

redis = Redis.new(host: REDIS_SERVER, port: REDIS_PORT, timeout: 30)

REDIS_DBS.each do |redis_db|
  redis.select(redis_db)
  puts "Translating db ##{redis_db}..."
  seconds = Benchmark.realtime do
    dbsize = redis.dbsize.to_f
    inc_threshold = (dbsize/100.0).round
    i = 0
    old_keys = redis.keys("#{NAMESPACE_PREFIX}#{FROM_NAMESPACE}*")
    old_keys.each do |old_key|
      new_key = old_key.gsub(FROM_NAMESPACE, TO_NAMESPACE)
      redis.rename(old_key, new_key)
      print "#{((i/dbsize)*100.0).round}% complete\r" if (i % inc_threshold == 0) # on whole # % only
      i += 1
    end
  end
  puts "\nDone. It took #{seconds} seconds"
end
like image 163
Excalibur Avatar answered May 25 '26 05:05

Excalibur



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!