memcache-client の append と prependの対応

mecached 1.2.4から、元々ある文字列の前後に文字列を足す appendとかprependがサポートされた。これは統計情報をmemcachedに蓄積したい場合に便利なんだけど rubyのmemcache-client 1.50では対応していない

require 'memcache'
class MemCache
  def prepend(key, value, expiry = 0)
    concat(:preprend, key, value, expiry)
  end
  def append(key, value, expiry = 0)
    concat(:append, key, value, expiry)
  end
  def concat(func, key, value, expiry = 0)
    raise MemCacheError, "Update of readonly cache" if @readonly
    server, cache_key = request_setup key
    socket = server.socket
    method = func == :append ? 'append' : 'prepend'
    command = "#{method} #{cache_key} 0 #{expiry} #{value.size}\r\n#{value}\r\n"
    begin
      @mutex.lock if @multithread
      socket.write command
      result = socket.gets
      raise MemCacheError, $1.strip     if result =~ /^SERVER_ERROR (.*)/
      raise MemCacheError, "not stored #{key}" if result =~ /^NOT_STORED(.*)/
    rescue SocketError, SystemCallError, IOError => err
      server.close
      raise MemCacheError, err.message
    ensure
      @mutex.unlock if @multithread
    end
  end
end

これで一応動いている。サンプルコード

m = MemCache::new 'localhost:11211',
                           :namespace => 'test',
                           :c_threshold => 100_000,
                           :readonly    => false,
                           :multithread => true,
                           #:mutex => true,
                           :compression => false
m.set('key', 'set', 0 , true)
m.append('key', 'append')
m.prepend('key', 'prepend')
v = m.get('key', true)
p v

出力

prependsetappend

setやgetする際に必ず rawをtrueで渡さないと、Marshal.dumpした値が concatされるので、Marshal.load できないので注意