High-performance ETS-based state manager for multi-site asset storage and retrieval.
Manages runtime asset data (themes, CSS, JavaScript, configurations) with optimized storage using composite keys for multi-tenant applications. Designed for fast asset retrieval, efficient memory usage, and concurrent read/write operations.
Architecture
Uses a single ETS table with composite key structure:
- Composite Key:
{site_name, type}ensures uniqueness per site and asset type - Value Storage: Arbitrary data structures (maps, strings, binaries)
- Metadata: Hash validation and timestamp tracking
- Concurrent Access: Optimized for high read concurrency
Data Structure
Each asset record contains:
id: Site identifier for multi-tenant isolationtype: Asset type classification (theme, css, js, config, etc.)value: Asset content (maps, strings, or any serializable data)hash: Content hash for validation and change detectionupdated_at: Last modification timestamp
Key Features
- O(1) Asset Lookups: Direct access by site and type combination
- Multi-tenant Isolation: Site-based asset separation
- Flexible Storage: Support for any serializable data structure
- Batch Operations: Efficient bulk asset loading
- Hash Validation: Content integrity verification
- Memory Optimization: Direct value access without full record retrieval
- Concurrent Safety: Read/write concurrency optimization
Performance Characteristics
- Direct lookups: O(1)
- Site-based queries: O(n) where n = assets per site
- Memory usage: ~100-200 bytes per asset + content size
- Concurrent reads: Fully optimized
- Batch operations: ~5x faster than individual saves
Usage Examples
# Save theme assets
AssetsState.save(%{
id: "myblog",
type: "theme",
value: %{
css: "body { color: #333; }",
js: "console.log('Theme loaded');",
config: %{dark_mode: true}
},
hash: "abc123",
updated_at: DateTime.utc_now()
})
# Fast asset retrieval
{:ok, theme} = AssetsState.get("myblog", "theme")
# Direct value access for performance
css_content = AssetsState.get_value("myblog", "css")
# Site-wide asset management
all_assets = AssetsState.get_by_site("myblog")
# Batch loading for performance
AssetsState.save_batch([
%{id: "site1", type: "theme", value: theme_data, hash: "hash1", updated_at: now},
%{id: "site1", type: "config", value: config_data, hash: "hash2", updated_at: now}
])Asset Type Examples
- theme: Complete theme packages with CSS, JS, and configuration
- css: Compiled CSS stylesheets
- js: JavaScript bundles and libraries
- config: Site-specific configuration data
- templates: Compiled template data
- metadata: SEO and meta information
- cache: Processed content cache
Integration Patterns
- Theme Engine: Dynamic theme loading and switching
- Asset Pipeline: Runtime asset compilation and serving
- Multi-site Management: Site-isolated asset storage
- CDN Integration: Asset hash-based cache invalidation
- Development Tools: Hot-reload asset updates
Production Considerations
- Monitor memory usage with
stats/0function - Implement asset cleanup strategies for unused sites
- Use hash validation for content integrity
- Consider asset size limits for memory management
- Leverage batch operations for bulk updates
- Use direct value access for performance-critical paths
Summary
Functions
Returns a specification to start this module under a supervisor.
Clears all data from the table.
Returns the number of assets in the table.
Deletes an asset by ID and type. A no-op while this cache is not running.
Deletes all assets for a specific site. Returns the number of deleted assets.
Fast check if an asset exists by site_name and type.
Gets asset data by ID (site_name) and type using direct lookup (O(1)). Returns {:ok, asset} or {:error, :not_found}.
Gets asset data by ID (site_name) and type, returns nil if not found. Optimized for read performance.
Gets all assets in the table. Note: Use with caution for large datasets.
Gets all assets for a specific site (all types). Returns a list of assets for the site.
Gets all assets of a specific type across all sites. Note: This is less efficient than direct lookups.
Gets multiple assets by their composite keys {site_name, type}. Returns a list of found assets.
Gets only the value field for maximum read performance. Returns the raw value or nil if not found.
The hash of an asset without reading its (large) value — nil if absent.
Saves asset data to the ETS table with composite key (site_name, type).
Batch save multiple assets for better performance.
Starts the MishkaCmsCore.Runtime.States.AssetsState GenServer and creates the ETS table.
Returns detailed statistics about the assets table.
Updates the updated_at timestamp for an asset.
The types stored for a site, without reading their values.
Updates only the value field of an existing asset. Returns :ok if updated, {:error, :not_found} if asset doesn't exist.
The updated_at of an asset without reading its (large) value — nil if absent.
Functions
Returns a specification to start this module under a supervisor.
See Supervisor.
Clears all data from the table.
Returns the number of assets in the table.
Deletes an asset by ID and type. A no-op while this cache is not running.
Deletes all assets for a specific site. Returns the number of deleted assets.
Fast check if an asset exists by site_name and type.
Gets asset data by ID (site_name) and type using direct lookup (O(1)). Returns {:ok, asset} or {:error, :not_found}.
Gets asset data by ID (site_name) and type, returns nil if not found. Optimized for read performance.
Gets all assets in the table. Note: Use with caution for large datasets.
Gets all assets for a specific site (all types). Returns a list of assets for the site.
Gets all assets of a specific type across all sites. Note: This is less efficient than direct lookups.
Gets multiple assets by their composite keys {site_name, type}. Returns a list of found assets.
Gets only the value field for maximum read performance. Returns the raw value or nil if not found.
The hash of an asset without reading its (large) value — nil if absent.
One lookup that copies the hash alone, for the paths that run on every page render.
Saves asset data to the ETS table with composite key (site_name, type).
Examples
MishkaCmsCore.Runtime.States.AssetsState.save(%{
id: "example_site",
type: "theme",
value: %{css: "body { color: red; }", js: "console.log('hello');"},
hash: "hash_value",
updated_at: ~U[2024-01-01 10:00:00Z]
})
Batch save multiple assets for better performance.
Starts the MishkaCmsCore.Runtime.States.AssetsState GenServer and creates the ETS table.
Returns detailed statistics about the assets table.
Updates the updated_at timestamp for an asset.
The types stored for a site, without reading their values.
Updates only the value field of an existing asset. Returns :ok if updated, {:error, :not_found} if asset doesn't exist.
The updated_at of an asset without reading its (large) value — nil if absent.