Shell脚本如何实现LRU缓存

wen 实用脚本 6

本文目录导读:

Shell脚本如何实现LRU缓存

  1. 基础实现 - 使用文件系统
  2. 使用关联数组的内存版本
  3. 使用临时文件的增强版本
  4. 使用SQLite的持久化版本
  5. 完整测试脚本
  6. 最佳实践建议

我来详细介绍Shell脚本实现LRU(Least Recently Used)缓存的方法。

基础实现 - 使用文件系统

简单文件版本

#!/bin/bash
# LRU缓存文件路径
CACHE_FILE="/tmp/lru_cache.txt"
CACHE_MAX_SIZE=5
# 初始化缓存文件
init_cache() {
    if [ ! -f "$CACHE_FILE" ]; then
        touch "$CACHE_FILE"
    fi
}
# 获取缓存
cache_get() {
    local key="$1"
    local value
    # 查找key是否存在
    value=$(grep "^$key:" "$CACHE_FILE" 2>/dev/null | cut -d: -f2)
    if [ -n "$value" ]; then
        # 更新访问时间 - 将该项移到文件末尾
        grep -v "^$key:" "$CACHE_FILE" > "${CACHE_FILE}.tmp"
        echo "$key:$value" >> "${CACHE_FILE}.tmp"
        mv "${CACHE_FILE}.tmp" "$CACHE_FILE"
        echo "$value"
    fi
}
# 设置缓存
cache_set() {
    local key="$1"
    local value="$2"
    # 如果key已存在,先删除旧记录
    if grep -q "^$key:" "$CACHE_FILE" 2>/dev/null; then
        grep -v "^$key:" "$CACHE_FILE" > "${CACHE_FILE}.tmp"
        mv "${CACHE_FILE}.tmp" "$CACHE_FILE"
    fi
    # 添加新记录
    echo "$key:$value" >> "$CACHE_FILE"
    # 检查并清理超出大小的项目
    local lines=$(wc -l < "$CACHE_FILE")
    if [ "$lines" -gt "$CACHE_MAX_SIZE" ]; then
        # 删除最旧的项目(文件头部)
        tail -n "$CACHE_MAX_SIZE" "$CACHE_FILE" > "${CACHE_FILE}.tmp"
        mv "${CACHE_FILE}.tmp" "$CACHE_FILE"
    fi
}
# 删除缓存项
cache_del() {
    local key="$1"
    grep -v "^$key:" "$CACHE_FILE" > "${CACHE_FILE}.tmp"
    mv "${CACHE_FILE}.tmp" "$CACHE_FILE"
}
# 清空缓存
cache_clear() {
    > "$CACHE_FILE"
}
# 查看缓存状态
cache_status() {
    echo "=== LRU Cache Status ==="
    echo "Max Size: $CACHE_MAX_SIZE"
    echo "Current Size: $(wc -l < "$CACHE_FILE")"
    echo "Contents (least recent first):"
    cat "$CACHE_FILE" | while IFS=: read -r key value; do
        echo "  $key -> $value"
    done
}

使用关联数组的内存版本

#!/bin/bash
# 内存LRU缓存实现(使用关联数组)
declare -A LRU_CACHE
declare -a LRU_ORDER=()
CACHE_MAX_SIZE=10
# 获取缓存值
lru_get() {
    local key="$1"
    if [[ -v LRU_CACHE["$key"] ]]; then
        # 更新访问顺序
        update_access_order "$key"
        echo "${LRU_CACHE[$key]}"
        return 0
    fi
    return 1
}
# 设置缓存值
lru_set() {
    local key="$1"
    local value="$2"
    # 如果key已存在,更新值
    if [[ -v LRU_CACHE["$key"] ]]; then
        LRU_CACHE["$key"]="$value"
        update_access_order "$key"
    else
        # 检查缓存是否已满
        if [ ${#LRU_ORDER[@]} -ge "$CACHE_MAX_SIZE" ]; then
            # 移除最久未使用的项
            local oldest="${LRU_ORDER[0]}"
            unset LRU_CACHE["$oldest"]
            LRU_ORDER=("${LRU_ORDER[@]:1}")
        fi
        # 添加新项
        LRU_CACHE["$key"]="$value"
        LRU_ORDER+=("$key")
    fi
}
# 更新访问顺序
update_access_order() {
    local key="$1"
    local index=-1
    for i in "${!LRU_ORDER[@]}"; do
        if [ "${LRU_ORDER[$i]}" == "$key" ]; then
            index=$i
            break
        fi
    done
    if [ $index -ge 0 ]; then
        # 移除当前位置
        unset 'LRU_ORDER[$index]'
        # 重新索引数组
        LRU_ORDER=("${LRU_ORDER[@]}")
        # 添加到末尾
        LRU_ORDER+=("$key")
    fi
}
# 删除缓存项
lru_del() {
    local key="$1"
    if [[ -v LRU_CACHE["$key"] ]]; then
        unset LRU_CACHE["$key"]
        # 从顺序数组中移除
        for i in "${!LRU_ORDER[@]}"; do
            if [ "${LRU_ORDER[$i]}" == "$key" ]; then
                unset 'LRU_ORDER[$i]'
                LRU_ORDER=("${LRU_ORDER[@]}")
                break
            fi
        done
    fi
}
# 显示缓存状态
lru_status() {
    echo "=== Memory LRU Cache ==="
    echo "Max Size: $CACHE_MAX_SIZE"
    echo "Current Size: ${#LRU_CACHE[@]}"
    echo "Access Order (oldest first):"
    for key in "${LRU_ORDER[@]}"; do
        echo "  $key -> ${LRU_CACHE[$key]}"
    done
}

使用临时文件的增强版本

#!/bin/bash
# LRU缓存类
LRUCache() {
    # 构造函数
    local -n self=$1
    self[base_dir]="/tmp/lru_cache_$$"
    self[max_size]=10
    # 初始化
    mkdir -p "${self[base_dir]}"
    # 获取缓存
    get() {
        local key="$1"
        local cache_file="${self[base_dir]}/${key}"
        if [ -f "$cache_file" ]; then
            # 更新时间戳
            touch "$cache_file"
            cat "$cache_file"
            return 0
        fi
        return 1
    }
    # 设置缓存
    set() {
        local key="$1"
        local value="$2"
        local cache_file="${self[base_dir]}/${key}"
        echo "$value" > "$cache_file"
        # 检查并淘汰
        evict_if_needed
    }
    # 淘汰最久未使用的
    evict_if_needed() {
        local count=$(ls -1t "${self[base_dir]}/" 2>/dev/null | wc -l)
        if [ "$count" -gt "${self[max_size]}" ]; then
            # 找到最久未访问的文件并删除
            ls -1t "${self[base_dir]}/" | tail -n $((count - self[max_size])) | 
            while read file; do
                rm -f "${self[base_dir]}/$file"
            done
        fi
    }
    # 获取统计信息
    stats() {
        echo "Cache directory: ${self[base_dir]}"
        echo "Max size: ${self[max_size]}"
        echo "Current size: $(ls -1 "${self[base_dir]}/" 2>/dev/null | wc -l)"
        echo "Recent access order (most recent first):"
        ls -1t "${self[base_dir]}/" 2>/dev/null | head -10
    }
    # 清理
    cleanup() {
        rm -rf "${self[base_dir]}"
    }
}
# 使用示例
example_usage() {
    # 创建缓存实例
    declare -A my_cache
    LRUCache my_cache
    my_cache[max_size]=5
    # 设置缓存
    my_cache set "key1" "value1"
    my_cache set "key2" "value2"
    my_cache set "key3" "value3"
    # 获取缓存
    echo "key1 value: $(my_cache get 'key1')"
    # 显示状态
    my_cache stats
    # 清理
    my_cache cleanup
}

使用SQLite的持久化版本

#!/bin/bash
# SQLite LRU缓存实现
LRU_DB="/tmp/lru_cache.db"
# 初始化数据库
init_sqlite_cache() {
    sqlite3 "$LRU_DB" "CREATE TABLE IF NOT EXISTS cache (
        key TEXT PRIMARY KEY,
        value TEXT,
        access_time INTEGER
    );"
}
# 获取缓存
sqlite_cache_get() {
    local key="$1"
    init_sqlite_cache
    local result=$(sqlite3 "$LRU_DB" "SELECT value, access_time FROM cache WHERE key='$key'")
    if [ -n "$result" ]; then
        # 更新时间戳
        sqlite3 "$LRU_DB" "UPDATE cache SET access_time=$(date +%s) WHERE key='$key'"
        echo "$result" | cut -d'|' -f1
        return 0
    fi
    return 1
}
# 设置缓存
sqlite_cache_set() {
    local key="$1"
    local value="$2"
    local max_size=10
    init_sqlite_cache
    # 插入或更新
    sqlite3 "$LRU_DB" "INSERT OR REPLACE INTO cache (key, value, access_time) 
                       VALUES ('$key', '$value', $(date +%s))"
    # 检查并淘汰
    local count=$(sqlite3 "$LRU_DB" "SELECT COUNT(*) FROM cache")
    if [ "$count" -gt "$max_size" ]; then
        # 删除最久未使用的记录
        sqlite3 "$LRU_DB" "DELETE FROM cache WHERE key IN (
            SELECT key FROM cache ORDER BY access_time ASC LIMIT $((count - max_size))
        )"
    fi
}

完整测试脚本

#!/bin/bash
# 包含LRU实现
source ./lru_cache.sh
# 测试函数
test_lru_cache() {
    echo "=== Testing LRU Cache ==="
    # 使用内存版本
    echo "Testing memory cache..."
    lru_set "key1" "value1"
    lru_set "key2" "value2"
    lru_set "key3" "value3"
    echo "Get key1: $(lru_get 'key1')"
    echo "Get key2: $(lru_get 'key2')"
    lru_status
    # 测试淘汰
    echo -e "\nAdding more items to trigger eviction..."
    lru_set "key4" "value4"
    lru_set "key5" "value5"
    lru_set "key6" "value6"
    lru_status
    echo "Try to get evicted key (key3): $(lru_get 'key3' || echo 'NOT FOUND')"
}
# 执行测试
test_lru_cache

最佳实践建议

  1. 选择合适的实现方式

    • 小型缓存:使用关联数组
    • 持久化需求:使用文件或SQLite
    • 高性能需求:使用临时文件
  2. 并发安全

    • 使用文件锁处理并发访问
    • 考虑使用flock命令
  3. 性能优化

    • 使用哈希函数分散文件存储
    • 实现二级缓存策略
    • 定期清理过期项
  4. 错误处理

    • 检查文件操作是否成功
    • 处理并发写入冲突
    • 实现优雅的清理机制

这些实现可以根据你的具体需求进行调整和优化,选择哪种方式取决于你的使用场景、性能要求和数据持久化需求。

抱歉,评论功能暂时关闭!