Module: VibeZstd::ThreadLocal

Defined in:
lib/vibe_zstd.rb

Overview

Thread-local context pooling for high-performance reuse Ideal for Rails/Puma applications where threads are reused across requests

Example usage:

# In Rails model with encrypted attributes
class User < ApplicationRecord
  encrypts :email
  encrypts :preferences, dict: JSON_DICT
end

# Instead of:
VibeZstd.decompress(data, dict: dict)  # Creates new DCtx each time

# Use:
VibeZstd::ThreadLocal.decompress(data, dict: dict)  # Reuses DCtx per thread

Memory footprint: ~128KB per DCtx × unique dictionaries × threads Example: 3 dicts × 5 Puma threads = 1.9MB total

Storage: uses Thread#thread_variable_get/set (true thread-local) so that fiber-based servers (Falcon, async) share one pool per OS thread rather than allocating a fresh pool for every fiber.

Note: Only supports per-operation parameters (level, dict, pledged_size, initial_capacity) Does NOT support context-level settings (nb_workers, checksum_flag, etc.)

Class Method Summary collapse

Class Method Details

.clear_thread_cache!Object

Clear all thread-local context pools for the current thread Useful for testing or explicit memory management



167
168
169
170
171
# File 'lib/vibe_zstd.rb', line 167

def self.clear_thread_cache!
  Thread.current.thread_variable_set(:vibe_zstd_cctx_pool, {})
  Thread.current.thread_variable_set(:vibe_zstd_dctx_pool, {})
  nil
end

.compress(data, level: nil, dict: nil, pledged_size: nil) ⇒ String

Compress data using thread-local context pool Contexts are keyed by dictionary ID for automatic isolation

Parameters:

  • data (String)

    Data to compress

  • level (Integer) (defaults to: nil)

    Compression level (per-operation, can vary)

  • dict (CDict) (defaults to: nil)

    Compression dictionary (optional)

  • pledged_size (Integer) (defaults to: nil)

    Expected input size (optional)

Returns:

  • (String)

    Compressed data



121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
# File 'lib/vibe_zstd.rb', line 121

def self.compress(data, level: nil, dict: nil, pledged_size: nil)
  # Key by dictionary ID, or :default if no dict
  key = dict ? dict.dict_id : :default

  # Get or create thread-local context pool (true thread-local, not fiber-local)
  pool = Thread.current.thread_variable_get(:vibe_zstd_cctx_pool) || {}
  cctx = pool[key] ||= VibeZstd::CCtx.new
  Thread.current.thread_variable_set(:vibe_zstd_cctx_pool, pool)

  # Build options hash
  options = {}
  options[:level] = level if level
  options[:dict] = dict if dict
  options[:pledged_size] = pledged_size if pledged_size

  cctx.compress(data, **options)
end

.decompress(data, dict: nil, initial_capacity: nil, max_decompressed_size: nil) ⇒ String

Decompress data using thread-local context pool Contexts are keyed by dictionary ID for automatic isolation

Parameters:

  • data (String)

    Data to decompress

  • dict (DDict) (defaults to: nil)

    Decompression dictionary (optional)

  • initial_capacity (Integer) (defaults to: nil)

    Initial buffer size for unknown-size frames (optional)

  • max_decompressed_size (Integer) (defaults to: nil)

    Output-size limit; raises DecompressedSizeExceeded if exceeded (optional)

Returns:

  • (String)

    Decompressed data



147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
# File 'lib/vibe_zstd.rb', line 147

def self.decompress(data, dict: nil, initial_capacity: nil, max_decompressed_size: nil)
  key = dict ? dict.dict_id : :default

  # Get or create thread-local context pool (true thread-local, not fiber-local)
  pool = Thread.current.thread_variable_get(:vibe_zstd_dctx_pool) || {}
  dctx = pool[key] ||= VibeZstd::DCtx.new
  Thread.current.thread_variable_set(:vibe_zstd_dctx_pool, pool)

  # Build options hash
  options = {}
  options[:dict] = dict if dict
  options[:initial_capacity] = initial_capacity if initial_capacity
  options[:max_decompressed_size] = max_decompressed_size if max_decompressed_size

  # C code will validate dict matches frame requirements
  dctx.decompress(data, **options)
end

.thread_cache_statsHash

Get statistics about the current thread’s context pools

Returns:

  • (Hash)

    Pool statistics



175
176
177
178
179
180
181
182
183
184
# File 'lib/vibe_zstd.rb', line 175

def self.thread_cache_stats
  cctx_pool = Thread.current.thread_variable_get(:vibe_zstd_cctx_pool)
  dctx_pool = Thread.current.thread_variable_get(:vibe_zstd_dctx_pool)
  {
    compression_contexts: cctx_pool&.size || 0,
    decompression_contexts: dctx_pool&.size || 0,
    compression_keys: cctx_pool&.keys || [],
    decompression_keys: dctx_pool&.keys || []
  }
end