Module: Air18n::ChunkCache

Defined in:
lib/air18n/chunk_cache.rb

Constant Summary collapse

MAX_CHUNK_SIZE =

Define constants and cache keys.

We divide things into chunks of 900000 bytes to accomodate memcaches with 1mb max value size.

900000
CHECKSUM_CACHE_KEY =
"%s_0_nchunks+checksum"
CHUNK_CACHE_KEY =
"%s_%d"

Class Method Summary collapse

Class Method Details

.get(cache, key) ⇒ Object

This returns nil if the chunks are corrupt or missing.



38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# File 'lib/air18n/chunk_cache.rb', line 38

def get(cache, key)
  buffer = ""
  chunk = cache.read(CHECKSUM_CACHE_KEY % key)
  if chunk
    num_chunks, checksum = JSON.parse(chunk)
  else
    LoggingHelper.error "ChunkCache get: no checksum stored for #{key}"
    return nil
  end

  for i in 1..num_chunks
    chunk = cache.read(CHUNK_CACHE_KEY % [key, i])

    if chunk.nil?
      # Return nil if any chunk is missing.
      LoggingHelper.error "ChunkCache get: chunk #{CHUNK_CACHE_KEY % [key, i]} is missing"
      return nil
    end

    buffer << chunk
  end

  if Zlib::crc32(buffer) != checksum
    LoggingHelper.error "ChunkCache get: invalid checksum for #{key}"
    return nil
  else
    return JSON.parse(buffer)[0]
  end
end

.set(cache, key, value, expires_in) ⇒ Object



19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# File 'lib/air18n/chunk_cache.rb', line 19

def set(cache, key, value, expires_in)
  # We put the value in an array because plain strings are not valid JSON.
  value_json = [value].to_json

  # We use divmod to avoid the edge condition where the floating point math
  # result is 5.000001 and the ceil would result in 6.
  quotient, modulus = value_json.bytesize.divmod(MAX_CHUNK_SIZE)
  num_chunks = modulus > 0 ? quotient + 1 : quotient
  cache.write(CHECKSUM_CACHE_KEY % key, [num_chunks, Zlib::crc32(value_json)].to_json)

  1.upto(num_chunks) do |i|
    chunk = value_json.byteslice((i-1)*MAX_CHUNK_SIZE, MAX_CHUNK_SIZE)
    if cache.write(CHUNK_CACHE_KEY % [key, i], chunk, :expires_in => expires_in) == false
      LoggingHelper.error "ChunkCache set: failed to write chunk #{CHUNK_CACHE_KEY % [key, i]} (#{chunk.size} chars /  #{chunk.bytesize} bytes)"
    end
  end
end