์œ„์ ฏ ์บ์‹ฑ

์œ„์ ฏ ์บ์‹ฑ

์œ„์ ฏ์˜ ์„ฑ๋Šฅ์„ ํ–ฅ์ƒ์‹œํ‚ค๊ธฐ ์œ„ํ•œ ๋‹ค์–‘ํ•œ ์บ์‹ฑ ์ „๋žต์„ ํ•™์Šตํ•ฉ๋‹ˆ๋‹ค.

์บ์‹ฑ ๊ธฐ๋ณธ ๊ฐœ๋…

์บ์‹ฑ์ด ํ•„์š”ํ•œ ์ด์œ 

// ์บ์‹ฑ ์—†์ด ๋งค๋ฒˆ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์กฐํšŒ
function proc($args) {
    // ๋งค ์š”์ฒญ๋งˆ๋‹ค ์‹คํ–‰๋˜๋Š” ๋ฌด๊ฑฐ์šด ์ฟผ๋ฆฌ
    $output = executeQuery('complex.getHeavyData', $args);
    return $this->compileTemplate($args);
}

// ์บ์‹ฑ ์ ์šฉ ํ›„
function proc($args) {
    $cache_key = $this->getCacheKey($args);
    $cached_data = $this->getCache($cache_key);

    if ($cached_data) {
        Context::set('data', $cached_data);
        return $this->compileTemplate($args);
    }

    // ์บ์‹œ๊ฐ€ ์—†์„ ๋•Œ๋งŒ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์กฐํšŒ
    $output = executeQuery('complex.getHeavyData', $args);
    $this->setCache($cache_key, $output->data, 300); // 5๋ถ„ ์บ์‹ฑ

    Context::set('data', $output->data);
    return $this->compileTemplate($args);
}

ํŒŒ์ผ ๊ธฐ๋ฐ˜ ์บ์‹ฑ

๊ธฐ๋ณธ ํŒŒ์ผ ์บ์‹œ ๊ตฌํ˜„

class FileCache
{
    private $cache_dir;
    private $default_ttl = 3600; // 1์‹œ๊ฐ„

    public function __construct($cache_dir = null)
    {
        $this->cache_dir = $cache_dir ?: _XE_PATH_ . 'files/cache/widgets/';
        $this->ensureCacheDir();
    }

    /**
     * ์บ์‹œ ๋””๋ ‰ํ† ๋ฆฌ ์ƒ์„ฑ
     */
    private function ensureCacheDir()
    {
        if (!is_dir($this->cache_dir)) {
            FileHandler::makeDir($this->cache_dir);
        }
    }

    /**
     * ์บ์‹œ ํ‚ค ์ƒ์„ฑ
     */
    public function generateKey($prefix, $data)
    {
        return $prefix . '_' . md5(serialize($data));
    }

    /**
     * ์บ์‹œ ๋ฐ์ดํ„ฐ ์กฐํšŒ
     */
    public function get($key)
    {
        $cache_file = $this->cache_dir . $key . '.cache';

        if (!file_exists($cache_file)) {
            return null;
        }

        $cache_data = unserialize(file_get_contents($cache_file));

        // TTL ํ™•์ธ
        if (isset($cache_data['expires']) && time() > $cache_data['expires']) {
            $this->delete($key);
            return null;
        }

        return $cache_data['data'];
    }

    /**
     * ์บ์‹œ ๋ฐ์ดํ„ฐ ์ €์žฅ
     */
    public function set($key, $data, $ttl = null)
    {
        $ttl = $ttl ?: $this->default_ttl;
        $cache_file = $this->cache_dir . $key . '.cache';

        $cache_data = array(
            'data' => $data,
            'created' => time(),
            'expires' => time() + $ttl
        );

        file_put_contents($cache_file, serialize($cache_data));
    }

    /**
     * ์บ์‹œ ๋ฐ์ดํ„ฐ ์‚ญ์ œ
     */
    public function delete($key)
    {
        $cache_file = $this->cache_dir . $key . '.cache';
        if (file_exists($cache_file)) {
            unlink($cache_file);
        }
    }

    /**
     * ๋งŒ๋ฃŒ๋œ ์บ์‹œ ์ •๋ฆฌ
     */
    public function cleanup()
    {
        $files = glob($this->cache_dir . '*.cache');
        $cleaned = 0;

        foreach ($files as $file) {
            $cache_data = unserialize(file_get_contents($file));

            if (isset($cache_data['expires']) && time() > $cache_data['expires']) {
                unlink($file);
                $cleaned++;
            }
        }

        return $cleaned;
    }

    /**
     * ๋ชจ๋“  ์บ์‹œ ์‚ญ์ œ
     */
    public function flush()
    {
        $files = glob($this->cache_dir . '*.cache');
        foreach ($files as $file) {
            unlink($file);
        }
    }
}

์œ„์ ฏ์—์„œ ํŒŒ์ผ ์บ์‹œ ์‚ฌ์šฉ

class latest_posts_widget extends WidgetHandler
{
    private $cache;

    public function __construct()
    {
        $this->cache = new FileCache();
    }

    function proc($args)
    {
        // ์บ์‹œ ํ‚ค ์ƒ์„ฑ
        $cache_key = $this->cache->generateKey('latest_posts', array(
            'mid_list' => $args->mid_list,
            'list_count' => $args->list_count,
            'template' => $args->template,
            'cache_version' => $this->getCacheVersion()
        ));

        // ์บ์‹œ ํ™•์ธ
        $cached_data = $this->cache->get($cache_key);
        if ($cached_data) {
            Context::set('document_list', $cached_data);
            Context::set('from_cache', true);
            return $this->compileTemplate($args);
        }

        // ๋ฐ์ดํ„ฐ ์กฐํšŒ
        $document_list = $this->getDocumentList($args);

        // ํ›„์ฒ˜๋ฆฌ
        $document_list = $this->processDocuments($document_list, $args);

        // ์บ์‹œ ์ €์žฅ
        $cache_time = max(60, (int)$args->cache_time); // ์ตœ์†Œ 1๋ถ„
        $this->cache->set($cache_key, $document_list, $cache_time);

        Context::set('document_list', $document_list);
        Context::set('from_cache', false);

        return $this->compileTemplate($args);
    }

    /**
     * ์บ์‹œ ๋ฒ„์ „ ๊ด€๋ฆฌ
     */
    private function getCacheVersion()
    {
        // ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ๊ฐ€ ๋ณ€๊ฒฝ๋  ๋•Œ๋งˆ๋‹ค ๋ฒ„์ „ ์—…๋ฐ์ดํŠธ
        return '1.2.0';
    }
}

๋ฉ”๋ชจ๋ฆฌ ์บ์‹ฑ (APCu)

APCu ์บ์‹œ ๊ตฌํ˜„

class MemoryCache
{
    private $prefix;
    private $default_ttl = 3600;

    public function __construct($prefix = 'widget_')
    {
        $this->prefix = $prefix;
    }

    /**
     * APCu ์‚ฌ์šฉ ๊ฐ€๋Šฅ ์—ฌ๋ถ€ ํ™•์ธ
     */
    public function isAvailable()
    {
        return extension_loaded('apcu') && apcu_enabled();
    }

    /**
     * ์บ์‹œ ํ‚ค ์ƒ์„ฑ
     */
    private function getKey($key)
    {
        return $this->prefix . $key;
    }

    /**
     * ์บ์‹œ ๋ฐ์ดํ„ฐ ์กฐํšŒ
     */
    public function get($key)
    {
        if (!$this->isAvailable()) {
            return null;
        }

        $cache_key = $this->getKey($key);
        $success = false;
        $data = apcu_fetch($cache_key, $success);

        return $success ? $data : null;
    }

    /**
     * ์บ์‹œ ๋ฐ์ดํ„ฐ ์ €์žฅ
     */
    public function set($key, $data, $ttl = null)
    {
        if (!$this->isAvailable()) {
            return false;
        }

        $cache_key = $this->getKey($key);
        $ttl = $ttl ?: $this->default_ttl;

        return apcu_store($cache_key, $data, $ttl);
    }

    /**
     * ์บ์‹œ ๋ฐ์ดํ„ฐ ์‚ญ์ œ
     */
    public function delete($key)
    {
        if (!$this->isAvailable()) {
            return false;
        }

        return apcu_delete($this->getKey($key));
    }

    /**
     * ํŒจํ„ด์œผ๋กœ ์บ์‹œ ์‚ญ์ œ
     */
    public function deleteByPattern($pattern)
    {
        if (!$this->isAvailable()) {
            return false;
        }

        $iterator = new APCUIterator('/^' . preg_quote($this->prefix . $pattern, '/') . '/');
        return apcu_delete($iterator);
    }

    /**
     * ๋ชจ๋“  ์บ์‹œ ์‚ญ์ œ
     */
    public function flush()
    {
        if (!$this->isAvailable()) {
            return false;
        }

        return $this->deleteByPattern('');
    }
}

Redis ์บ์‹ฑ

Redis ์บ์‹œ ๊ตฌํ˜„

class RedisCache
{
    private $redis;
    private $prefix;
    private $default_ttl = 3600;
    private $connected = false;

    public function __construct($config = array())
    {
        $this->prefix = $config['prefix'] ?: 'widget:';

        if (class_exists('Redis')) {
            $this->redis = new Redis();
            $this->connect($config);
        }
    }

    /**
     * Redis ์—ฐ๊ฒฐ
     */
    private function connect($config)
    {
        try {
            $host = $config['host'] ?: '127.0.0.1';
            $port = $config['port'] ?: 6379;
            $timeout = $config['timeout'] ?: 2.5;

            $this->connected = $this->redis->connect($host, $port, $timeout);

            if ($this->connected && !empty($config['password'])) {
                $this->redis->auth($config['password']);
            }

            if ($this->connected && !empty($config['database'])) {
                $this->redis->select($config['database']);
            }

        } catch (Exception $e) {
            $this->connected = false;
        }
    }

    /**
     * Redis ์‚ฌ์šฉ ๊ฐ€๋Šฅ ์—ฌ๋ถ€ ํ™•์ธ
     */
    public function isAvailable()
    {
        return $this->connected;
    }

    /**
     * ์บ์‹œ ํ‚ค ์ƒ์„ฑ
     */
    private function getKey($key)
    {
        return $this->prefix . $key;
    }

    /**
     * ์บ์‹œ ๋ฐ์ดํ„ฐ ์กฐํšŒ
     */
    public function get($key)
    {
        if (!$this->isAvailable()) {
            return null;
        }

        try {
            $data = $this->redis->get($this->getKey($key));
            return $data ? unserialize($data) : null;
        } catch (Exception $e) {
            return null;
        }
    }

    /**
     * ์บ์‹œ ๋ฐ์ดํ„ฐ ์ €์žฅ
     */
    public function set($key, $data, $ttl = null)
    {
        if (!$this->isAvailable()) {
            return false;
        }

        try {
            $cache_key = $this->getKey($key);
            $serialized_data = serialize($data);
            $ttl = $ttl ?: $this->default_ttl;

            return $this->redis->setex($cache_key, $ttl, $serialized_data);
        } catch (Exception $e) {
            return false;
        }
    }

    /**
     * ์บ์‹œ ๋ฐ์ดํ„ฐ ์‚ญ์ œ
     */
    public function delete($key)
    {
        if (!$this->isAvailable()) {
            return false;
        }

        try {
            return $this->redis->del($this->getKey($key));
        } catch (Exception $e) {
            return false;
        }
    }

    /**
     * ํŒจํ„ด์œผ๋กœ ์บ์‹œ ์‚ญ์ œ
     */
    public function deleteByPattern($pattern)
    {
        if (!$this->isAvailable()) {
            return false;
        }

        try {
            $keys = $this->redis->keys($this->prefix . $pattern);
            if ($keys) {
                return $this->redis->del($keys);
            }
            return 0;
        } catch (Exception $e) {
            return false;
        }
    }

    /**
     * ์บ์‹œ ํ†ต๊ณ„
     */
    public function getStats()
    {
        if (!$this->isAvailable()) {
            return array();
        }

        try {
            return $this->redis->info();
        } catch (Exception $e) {
            return array();
        }
    }
}

๋‹ค์ธต ์บ์‹ฑ ์ „๋žต

์บ์‹œ ๊ณ„์ธต ๊ด€๋ฆฌ์ž

class MultiLevelCache
{
    private $caches = array();
    private $levels = array('memory', 'file', 'redis');

    public function __construct()
    {
        // ์บ์‹œ ๋ ˆ๋ฒจ๋ณ„ ์ธ์Šคํ„ด์Šค ์ƒ์„ฑ
        $this->caches['memory'] = new MemoryCache();
        $this->caches['file'] = new FileCache();
        $this->caches['redis'] = new RedisCache();
    }

    /**
     * ์บ์‹œ ๋ฐ์ดํ„ฐ ์กฐํšŒ (์ƒ์œ„ ๋ ˆ๋ฒจ๋ถ€ํ„ฐ)
     */
    public function get($key)
    {
        foreach ($this->levels as $level) {
            $cache = $this->caches[$level];

            if (!$cache->isAvailable()) {
                continue;
            }

            $data = $cache->get($key);
            if ($data !== null) {
                // ์ƒ์œ„ ๋ ˆ๋ฒจ ์บ์‹œ์— ๋ฐ์ดํ„ฐ ๋ณต์‚ฌ
                $this->backfillCache($key, $data, $level);
                return $data;
            }
        }

        return null;
    }

    /**
     * ์บ์‹œ ๋ฐ์ดํ„ฐ ์ €์žฅ (๋ชจ๋“  ๋ ˆ๋ฒจ์—)
     */
    public function set($key, $data, $ttl = null)
    {
        $success = false;

        foreach ($this->levels as $level) {
            $cache = $this->caches[$level];

            if ($cache->isAvailable()) {
                // ๋ ˆ๋ฒจ๋ณ„ TTL ์กฐ์ •
                $level_ttl = $this->adjustTTL($ttl, $level);
                if ($cache->set($key, $data, $level_ttl)) {
                    $success = true;
                }
            }
        }

        return $success;
    }

    /**
     * ์ƒ์œ„ ๋ ˆ๋ฒจ ์บ์‹œ ๋ฐฑํ•„
     */
    private function backfillCache($key, $data, $current_level)
    {
        $current_index = array_search($current_level, $this->levels);

        // ํ˜„์žฌ ๋ ˆ๋ฒจ๋ณด๋‹ค ์ƒ์œ„ ๋ ˆ๋ฒจ์— ๋ฐ์ดํ„ฐ ์ €์žฅ
        for ($i = 0; $i < $current_index; $i++) {
            $level = $this->levels[$i];
            $cache = $this->caches[$level];

            if ($cache->isAvailable()) {
                $cache->set($key, $data, $this->adjustTTL(null, $level));
            }
        }
    }

    /**
     * ๋ ˆ๋ฒจ๋ณ„ TTL ์กฐ์ •
     */
    private function adjustTTL($ttl, $level)
    {
        $default_ttl = $ttl ?: 3600;

        switch ($level) {
            case 'memory':
                return min($default_ttl, 300); // ๋ฉ”๋ชจ๋ฆฌ๋Š” 5๋ถ„ ์ตœ๋Œ€
            case 'file':
                return $default_ttl;
            case 'redis':
                return $default_ttl * 2; // Redis๋Š” ๋” ์˜ค๋ž˜ ๋ณด๊ด€
        }

        return $default_ttl;
    }

    /**
     * ์บ์‹œ ๋ฐ์ดํ„ฐ ์‚ญ์ œ (๋ชจ๋“  ๋ ˆ๋ฒจ์—์„œ)
     */
    public function delete($key)
    {
        foreach ($this->levels as $level) {
            $cache = $this->caches[$level];

            if ($cache->isAvailable()) {
                $cache->delete($key);
            }
        }
    }

    /**
     * ์บ์‹œ ํ†ต๊ณ„
     */
    public function getStats()
    {
        $stats = array();

        foreach ($this->levels as $level) {
            $cache = $this->caches[$level];
            $stats[$level] = array(
                'available' => $cache->isAvailable(),
                'stats' => method_exists($cache, 'getStats') ? $cache->getStats() : array()
            );
        }

        return $stats;
    }
}

์œ„์ ฏ์—์„œ ๋‹ค์ธต ์บ์‹ฑ ์‚ฌ์šฉ

class optimized_widget extends WidgetHandler
{
    private $cache;

    public function __construct()
    {
        $this->cache = new MultiLevelCache();
    }

    function proc($args)
    {
        // ์บ์‹œ ํ‚ค ์ƒ์„ฑ
        $cache_key = $this->generateCacheKey($args);

        // ์บ์‹œ ํ™•์ธ
        $cached_data = $this->cache->get($cache_key);
        if ($cached_data) {
            Context::set('data', $cached_data['data']);
            Context::set('cache_info', $cached_data['cache_info']);
            return $this->compileTemplate($args);
        }

        // ๋ฐ์ดํ„ฐ ์กฐํšŒ ๋ฐ ์ฒ˜๋ฆฌ
        $data = $this->processData($args);

        // ์บ์‹œ ์ •๋ณด ์ถ”๊ฐ€
        $cache_data = array(
            'data' => $data,
            'cache_info' => array(
                'generated_at' => time(),
                'version' => $this->getCacheVersion()
            )
        );

        // ์บ์‹œ ์ €์žฅ
        $this->cache->set($cache_key, $cache_data, $args->cache_time);

        Context::set('data', $data);
        Context::set('cache_info', $cache_data['cache_info']);

        return $this->compileTemplate($args);
    }

    private function generateCacheKey($args)
    {
        $key_data = array(
            'widget' => get_class($this),
            'args' => $this->normalizeArgs($args),
            'version' => $this->getCacheVersion()
        );

        return 'widget_' . md5(serialize($key_data));
    }

    private function normalizeArgs($args)
    {
        // ์บ์‹œ ํ‚ค์— ์˜ํ–ฅ์„ ์ฃผ๋Š” ์ธ์ˆ˜๋งŒ ์ถ”์ถœ
        return array(
            'mid_list' => $args->mid_list,
            'list_count' => $args->list_count,
            'template' => $args->template,
            'show_thumbnail' => $args->show_thumbnail
        );
    }
}

์บ์‹œ ๋ฌดํšจํ™” ์ „๋žต

์ด๋ฒคํŠธ ๊ธฐ๋ฐ˜ ์บ์‹œ ๋ฌดํšจํ™”

class CacheInvalidator
{
    private $cache;
    private $patterns = array();

    public function __construct($cache)
    {
        $this->cache = $cache;
        $this->registerEventHandlers();
    }

    /**
     * ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ ๋“ฑ๋ก
     */
    private function registerEventHandlers()
    {
        // ๊ฒŒ์‹œ๋ฌผ ๋“ฑ๋ก/์ˆ˜์ •/์‚ญ์ œ ์‹œ ์บ์‹œ ๋ฌดํšจํ™”
        EventHandler::addHandler('board.insertDocument', array($this, 'invalidateDocumentCache'));
        EventHandler::addHandler('board.updateDocument', array($this, 'invalidateDocumentCache'));
        EventHandler::addHandler('board.deleteDocument', array($this, 'invalidateDocumentCache'));

        // ๋Œ“๊ธ€ ๋“ฑ๋ก/์‚ญ์ œ ์‹œ ์บ์‹œ ๋ฌดํšจํ™”
        EventHandler::addHandler('board.insertComment', array($this, 'invalidateCommentCache'));
        EventHandler::addHandler('board.deleteComment', array($this, 'invalidateCommentCache'));
    }

    /**
     * ๊ฒŒ์‹œ๋ฌผ ๊ด€๋ จ ์บ์‹œ ๋ฌดํšจํ™”
     */
    public function invalidateDocumentCache($obj)
    {
        $module_srl = $obj->module_srl;

        // ํ•ด๋‹น ๊ฒŒ์‹œํŒ์˜ ๋ชจ๋“  ์œ„์ ฏ ์บ์‹œ ์‚ญ์ œ
        $patterns = array(
            'widget_*_mid_*_' . $module_srl . '_*',
            'widget_*_module_' . $module_srl . '_*',
            'latest_posts_*_' . $module_srl
        );

        foreach ($patterns as $pattern) {
            $this->cache->deleteByPattern($pattern);
        }
    }

    /**
     * ๋Œ“๊ธ€ ๊ด€๋ จ ์บ์‹œ ๋ฌดํšจํ™”
     */
    public function invalidateCommentCache($obj)
    {
        // ๋Œ“๊ธ€ ์ˆ˜๊ฐ€ ๋ณ€๊ฒฝ๋˜๋ฏ€๋กœ ๊ด€๋ จ ์บ์‹œ ๋ฌดํšจํ™”
        $this->invalidateDocumentCache($obj);
    }

    /**
     * ํŠน์ • ํŒจํ„ด์œผ๋กœ ์บ์‹œ ๋ฌดํšจํ™”
     */
    public function invalidateByPattern($pattern)
    {
        return $this->cache->deleteByPattern($pattern);
    }

    /**
     * ์‹œ๊ฐ„ ๊ธฐ๋ฐ˜ ์บ์‹œ ์ •๋ฆฌ
     */
    public function scheduleCleanup()
    {
        // ๋งค์ผ ์ƒˆ๋ฒฝ 3์‹œ์— ๋งŒ๋ฃŒ๋œ ์บ์‹œ ์ •๋ฆฌ
        if (date('H') == 3 && date('i') < 10) {
            $this->cache->cleanup();
        }
    }
}

์บ์‹œ ์„ฑ๋Šฅ ๋ชจ๋‹ˆํ„ฐ๋ง

์บ์‹œ ์„ฑ๋Šฅ ์ถ”์ 

class CacheMonitor
{
    private static $stats = array(
        'hits' => 0,
        'misses' => 0,
        'sets' => 0,
        'deletes' => 0,
        'total_time' => 0
    );

    /**
     * ์บ์‹œ ํžˆํŠธ ๊ธฐ๋ก
     */
    public static function recordHit($cache_key, $execution_time = 0)
    {
        self::$stats['hits']++;
        self::$stats['total_time'] += $execution_time;

        self::logAccess('HIT', $cache_key, $execution_time);
    }

    /**
     * ์บ์‹œ ๋ฏธ์Šค ๊ธฐ๋ก
     */
    public static function recordMiss($cache_key, $execution_time = 0)
    {
        self::$stats['misses']++;
        self::$stats['total_time'] += $execution_time;

        self::logAccess('MISS', $cache_key, $execution_time);
    }

    /**
     * ์บ์‹œ ์ €์žฅ ๊ธฐ๋ก
     */
    public static function recordSet($cache_key)
    {
        self::$stats['sets']++;
        self::logAccess('SET', $cache_key);
    }

    /**
     * ์บ์‹œ ์‚ญ์ œ ๊ธฐ๋ก
     */
    public static function recordDelete($cache_key)
    {
        self::$stats['deletes']++;
        self::logAccess('DELETE', $cache_key);
    }

    /**
     * ์•ก์„ธ์Šค ๋กœ๊ทธ ๊ธฐ๋ก
     */
    private static function logAccess($action, $cache_key, $execution_time = 0)
    {
        if (!__DEBUG__) {
            return;
        }

        $log_entry = array(
            'timestamp' => microtime(true),
            'action' => $action,
            'key' => $cache_key,
            'execution_time' => $execution_time,
            'memory_usage' => memory_get_usage(true)
        );

        $log_file = _XE_PATH_ . 'files/cache/cache_access.log';
        file_put_contents($log_file, json_encode($log_entry) . "\n", FILE_APPEND);
    }

    /**
     * ์บ์‹œ ํ†ต๊ณ„ ๋ฐ˜ํ™˜
     */
    public static function getStats()
    {
        $total_requests = self::$stats['hits'] + self::$stats['misses'];
        $hit_ratio = $total_requests > 0 ? (self::$stats['hits'] / $total_requests) * 100 : 0;

        return array(
            'hits' => self::$stats['hits'],
            'misses' => self::$stats['misses'],
            'hit_ratio' => round($hit_ratio, 2),
            'total_requests' => $total_requests,
            'sets' => self::$stats['sets'],
            'deletes' => self::$stats['deletes'],
            'average_time' => $total_requests > 0 ? self::$stats['total_time'] / $total_requests : 0
        );
    }

    /**
     * ํ†ต๊ณ„ ๋ฆฌ์…‹
     */
    public static function resetStats()
    {
        self::$stats = array(
            'hits' => 0,
            'misses' => 0,
            'sets' => 0,
            'deletes' => 0,
            'total_time' => 0
        );
    }
}

์บ์‹œ ์„ค์ • ๊ด€๋ฆฌ

์œ„์ ฏ๋ณ„ ์บ์‹œ ์„ค์ •

class WidgetCacheConfig
{
    private static $configs = array();

    /**
     * ์œ„์ ฏ๋ณ„ ์บ์‹œ ์„ค์ • ๋กœ๋“œ
     */
    public static function loadConfig($widget_name)
    {
        if (isset(self::$configs[$widget_name])) {
            return self::$configs[$widget_name];
        }

        $config_file = _XE_PATH_ . 'files/config/widget_cache/' . $widget_name . '.json';

        if (file_exists($config_file)) {
            $config = json_decode(file_get_contents($config_file), true);
        } else {
            $config = self::getDefaultConfig();
        }

        self::$configs[$widget_name] = $config;
        return $config;
    }

    /**
     * ๊ธฐ๋ณธ ์บ์‹œ ์„ค์ •
     */
    private static function getDefaultConfig()
    {
        return array(
            'enabled' => true,
            'default_ttl' => 300,
            'max_ttl' => 3600,
            'cache_levels' => array('memory', 'file'),
            'invalidation_events' => array(
                'board.insertDocument',
                'board.updateDocument',
                'board.deleteDocument'
            ),
            'cache_key_prefix' => 'widget',
            'compression' => false
        );
    }

    /**
     * ์บ์‹œ ์„ค์ • ์ €์žฅ
     */
    public static function saveConfig($widget_name, $config)
    {
        $config_dir = _XE_PATH_ . 'files/config/widget_cache/';
        if (!is_dir($config_dir)) {
            FileHandler::makeDir($config_dir);
        }

        $config_file = $config_dir . $widget_name . '.json';
        file_put_contents($config_file, json_encode($config, JSON_PRETTY_PRINT));

        self::$configs[$widget_name] = $config;
    }
}

๋ชจ๋ฒ” ์‚ฌ๋ก€

  1. ์ ์ ˆํ•œ TTL: ๋ฐ์ดํ„ฐ ํŠน์„ฑ์— ๋งž๋Š” ์บ์‹œ ์œ ํšจ ์‹œ๊ฐ„ ์„ค์ •
  2. ๊ณ„์ธต์  ์บ์‹ฑ: ๋น ๋ฅธ ๋ฉ”๋ชจ๋ฆฌ ์บ์‹œ์™€ ์˜๊ตฌ ์ €์žฅ์†Œ ์กฐํ•ฉ
  3. ๋ฌดํšจํ™” ์ „๋žต: ๋ฐ์ดํ„ฐ ๋ณ€๊ฒฝ ์‹œ ๊ด€๋ จ ์บ์‹œ ์ ์ ˆํžˆ ์‚ญ์ œ
  4. ๋ชจ๋‹ˆํ„ฐ๋ง: ์บ์‹œ ํžˆํŠธ์œจ๊ณผ ์„ฑ๋Šฅ ์ง€ํ‘œ ์ถ”์ 
  5. ์„ค์ • ๊ด€๋ฆฌ: ์œ„์ ฏ๋ณ„ ์บ์‹œ ์ •์ฑ… ์œ ์—ฐํ•˜๊ฒŒ ๊ด€๋ฆฌ

๋‹ค์Œ ๋‹จ๊ณ„

์œ„์ ฏ ์บ์‹ฑ์„ ๋งˆ์Šคํ„ฐํ–ˆ๋‹ค๋ฉด, ํŒŒ์ผ ๊ด€๋ฆฌ์—์„œ ์ฝ˜ํ…์ธ  ๊ด€๋ฆฌ๋ฅผ ํ•™์Šตํ•˜์„ธ์š”.