/
VirusVK
/
ServerIT
Обзор
Документация
Войти
/
VirusVK
/
ServerIT
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
armdb/src/core/cache.c
204 строки
6 KB
VirusVK
upload files
13 дек 2025, 14:28
13 дек 2025, 14:28
a626524
Код
Авторство
О чём код?
#include <stdlib.h> #include <string.h> #include <pthread.h> #include "storage.h" #define CACHE_SIZE 100 /* Запись в кэше */ typedef struct CacheEntry { uint64_t page_num; Page page; bool dirty; uint64_t last_used; struct CacheEntry *next; struct CacheEntry *prev; struct CacheEntry *next_hash; struct CacheEntry *prev_hash; } CacheEntry; /* Кэш страниц */ typedef struct { CacheEntry *entries[CACHE_SIZE]; CacheEntry *lru_head; CacheEntry *lru_tail; pthread_mutex_t lock; uint64_t access_time; size_t hit_count; size_t miss_count; } Cache; /* Инициализация кэша */ Cache *cache_init(void) { Cache *cache = calloc(1, sizeof(Cache)); if (!cache) return NULL; pthread_mutex_init(&cache->lock, NULL); return cache; } /* Освобождение кэша */ void cache_free(Cache *cache) { if (!cache) return; pthread_mutex_destroy(&cache->lock); // Освобождаем все записи CacheEntry *current = cache->lru_head; while (current) { CacheEntry *next = current->next; free(current); current = next; } free(cache); } /* Поиск страницы в кэше */ static CacheEntry *cache_find(Cache *cache, uint64_t page_num) { size_t idx = page_num % CACHE_SIZE; CacheEntry *entry = cache->entries[idx]; while (entry) { if (entry->page_num == page_num) { // Перемещаем в начало LRU if (entry != cache->lru_head) { // Удаляем из текущей позиции if (entry->prev) entry->prev->next = entry->next; if (entry->next) entry->next->prev = entry->prev; if (entry == cache->lru_tail) cache->lru_tail = entry->prev; // Добавляем в начало entry->next = cache->lru_head; entry->prev = NULL; if (cache->lru_head) cache->lru_head->prev = entry; cache->lru_head = entry; if (!cache->lru_tail) cache->lru_tail = entry; } entry->last_used = ++cache->access_time; cache->hit_count++; return entry; } entry = entry->next_hash; } cache->miss_count++; return NULL; } /* Добавление страницы в кэш */ static CacheEntry *cache_put(Cache *cache, uint64_t page_num, const Page *page) { size_t idx = page_num % CACHE_SIZE; CacheEntry *entry = calloc(1, sizeof(CacheEntry)); if (!entry) return NULL; entry->page_num = page_num; memcpy(&entry->page, page, sizeof(Page)); entry->last_used = ++cache->access_time; // Добавляем в хеш-таблицу entry->next_hash = cache->entries[idx]; if (cache->entries[idx]) cache->entries[idx]->prev_hash = entry; cache->entries[idx] = entry; // Добавляем в начало LRU entry->next = cache->lru_head; if (cache->lru_head) cache->lru_head->prev = entry; cache->lru_head = entry; if (!cache->lru_tail) cache->lru_tail = entry; return entry; } /* Вытеснение LRU страницы */ static CacheEntry *cache_evict(Cache *cache) { if (!cache->lru_tail) return NULL; CacheEntry *victim = cache->lru_tail; // Удаляем из хеш-таблицы size_t idx = victim->page_num % CACHE_SIZE; if (victim->prev_hash) victim->prev_hash->next_hash = victim->next_hash; if (victim->next_hash) victim->next_hash->prev_hash = victim->prev_hash; if (cache->entries[idx] == victim) cache->entries[idx] = victim->next_hash; // Удаляем из LRU if (victim->prev) victim->prev->next = victim->next; if (victim->next) victim->next->prev = victim->prev; if (cache->lru_head == victim) cache->lru_head = victim->next; if (cache->lru_tail == victim) cache->lru_tail = victim->prev; return victim; } /* Чтение страницы с кэшированием */ int cache_read(Database *db, Cache *cache, uint64_t page_num, Page *page) { if (!cache || !db || !page) return -1; pthread_mutex_lock(&cache->lock); CacheEntry *entry = cache_find(cache, page_num); if (entry) { memcpy(page, &entry->page, sizeof(Page)); pthread_mutex_unlock(&cache->lock); return 0; } // Читаем с диска int rc = db_read_page(db, page_num, page); if (rc == 0) { // Если кэш полон, вытесняем старую запись // TODO: подсчет записей в кэше и проверка на переполнение CacheEntry *evicted = cache_evict(cache); if (evicted) { // Если страница изменена, записываем на диск if (evicted->dirty) { db_write_page(db, evicted->page_num, &evicted->page); } free(evicted); } cache_put(cache, page_num, page); } pthread_mutex_unlock(&cache->lock); return rc; } /* Запись страницы с кэшированием */ int cache_write(Database *db, Cache *cache, uint64_t page_num, const Page *page) { if (!cache || !db || !page) return -1; pthread_mutex_lock(&cache->lock); CacheEntry *entry = cache_find(cache, page_num); if (entry) { memcpy(&entry->page, page, sizeof(Page)); entry->dirty = true; entry->last_used = ++cache->access_time; } else { // Создаем новую запись в кэше entry = cache_put(cache, page_num, page); if (entry) { entry->dirty = true; } } pthread_mutex_unlock(&cache->lock); // Отложенная запись на диск (write-back) return 0; } /* Статистика кэша */ void cache_stats(const Cache *cache) { if (!cache) return; printf("=== Статистика кэша ===\n"); printf("Попаданий: %zu\n", cache->hit_count); printf("Промахов: %zu\n", cache->miss_count); printf("Эффективность: %.2f%%\n", cache->hit_count * 100.0 / (cache->hit_count + cache->miss_count)); }