MishkaCmsCore.Runtime.States.AssetsState (Mishka CMS Core v0.0.1)

Copy Markdown View Source

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 isolation
  • type: Asset type classification (theme, css, js, config, etc.)
  • value: Asset content (maps, strings, or any serializable data)
  • hash: Content hash for validation and change detection
  • updated_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/0 function
  • 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

child_spec(init_arg)

Returns a specification to start this module under a supervisor.

See Supervisor.

clear()

Clears all data from the table.

count()

Returns the number of assets in the table.

delete(id, type)

Deletes an asset by ID and type. A no-op while this cache is not running.

delete_by_site(site_name)

Deletes all assets for a specific site. Returns the number of deleted assets.

exists?(id, type)

Fast check if an asset exists by site_name and type.

get(id, type)

Gets asset data by ID (site_name) and type using direct lookup (O(1)). Returns {:ok, asset} or {:error, :not_found}.

get!(id, type)

Gets asset data by ID (site_name) and type, returns nil if not found. Optimized for read performance.

get_all()

Gets all assets in the table. Note: Use with caution for large datasets.

get_by_site(site_name)

Gets all assets for a specific site (all types). Returns a list of assets for the site.

get_by_type(type)

Gets all assets of a specific type across all sites. Note: This is less efficient than direct lookups.

get_many(keys)

Gets multiple assets by their composite keys {site_name, type}. Returns a list of found assets.

get_value(id, type)

Gets only the value field for maximum read performance. Returns the raw value or nil if not found.

hash(id, type)

@spec hash(String.t(), String.t()) :: String.t() | nil

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.

save(attrs)

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]
})

save_batch(assets)

Batch save multiple assets for better performance.

start_link(opts \\ [])

Starts the MishkaCmsCore.Runtime.States.AssetsState GenServer and creates the ETS table.

stats()

Returns detailed statistics about the assets table.

touch(id, type)

Updates the updated_at timestamp for an asset.

types(site_name)

@spec types(String.t()) :: [String.t()]

The types stored for a site, without reading their values.

update_value(id, type, new_value)

Updates only the value field of an existing asset. Returns :ok if updated, {:error, :not_found} if asset doesn't exist.

updated_at(id, type)

The updated_at of an asset without reading its (large) value — nil if absent.