shtr_cache.c (3989B)
1 /* Copyright (C) 2022, 2025, 2026 |Méso|Star> (contact@meso-star.com) 2 * Copyright (C) 2025, 2026 Université de Lorraine 3 * Copyright (C) 2022 Centre National de la Recherche Scientifique 4 * Copyright (C) 2022 Université Paul Sabatier 5 * 6 * This program is free software: you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation, either version 3 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program. If not, see <http://www.gnu.org/licenses/>. */ 18 19 #include "shtr_c.h" 20 #include "shtr_cache.h" 21 22 #include <rsys/cstr.h> 23 #include <rsys/mutex.h> 24 #include <rsys/ref_count.h> 25 26 #include <string.h> /* memcpy */ 27 28 #define CHUNK_ID_NONE SIZE_MAX 29 30 /* Simple, dumb cache structure storing uncompressed lines from the last chunk 31 * accessed. It should improve linear access performance, but not random access 32 * performance, which will be disastrous because most accesses will require 33 * decompressing an entire block of lines, only one of which will be accessed 34 * before the block is discarded. 35 * 36 * TODO: implement a more general LRU cache */ 37 struct cache { 38 size_t chunk_id; 39 struct line lines[NLINES_PER_CHUNK]; 40 41 struct mutex* mutex; 42 struct shtr* shtr; 43 ref_T ref; 44 }; 45 46 /******************************************************************************* 47 * Helper functions 48 ******************************************************************************/ 49 static void 50 release_cache(ref_T* ref) 51 { 52 struct cache* cache = CONTAINER_OF(ref, struct cache, ref); 53 struct shtr* shtr = NULL; 54 ASSERT(ref); 55 shtr = cache->shtr; 56 if(cache->mutex) mutex_destroy(cache->mutex); 57 MEM_RM(shtr->allocator, cache); 58 SHTR(ref_put(shtr)); 59 } 60 61 /******************************************************************************* 62 * Local functions 63 ******************************************************************************/ 64 res_T 65 cache_create(struct shtr* shtr, struct cache** out_cache) 66 { 67 struct cache* cache = NULL; 68 res_T res = RES_OK; 69 70 ASSERT(shtr && out_cache); /* Pre-conditions */ 71 72 cache = MEM_CALLOC(shtr->allocator, 1, sizeof(*cache)); 73 if(!cache) { res = RES_MEM_ERR; goto error; } 74 ref_init(&cache->ref); 75 SHTR(ref_get(shtr)); 76 cache->shtr = shtr; 77 cache->chunk_id = CHUNK_ID_NONE; 78 79 cache->mutex = mutex_create(); 80 if(!cache->mutex) { res = RES_MEM_ERR; goto error; } 81 82 exit: 83 *out_cache = cache; 84 return res; 85 error: 86 ERROR(shtr, "Error creating line cache -- %s\n", res_to_cstr(res)); 87 if(cache) { cache_ref_put(cache); cache = NULL; } 88 goto exit; 89 } 90 91 void 92 cache_ref_get(struct cache* cache) 93 { 94 ASSERT(cache); 95 ref_get(&cache->ref); 96 } 97 98 void 99 cache_ref_put(struct cache* cache) 100 { 101 ASSERT(cache); 102 ref_put(&cache->ref, release_cache); 103 } 104 105 res_T 106 cache_get_line 107 (struct cache* cache, 108 const size_t line_id, 109 struct line* line) 110 { 111 const size_t chunk_id = line_id / NLINES_PER_CHUNK; 112 const size_t chunk_line_id = line_id % NLINES_PER_CHUNK; 113 res_T res = RES_OK; 114 115 ASSERT(cache && line); 116 ASSERT(chunk_id != CHUNK_ID_NONE && chunk_line_id < NLINES_PER_CHUNK); 117 118 mutex_lock(cache->mutex); 119 if(cache->chunk_id != chunk_id) { 120 res = RES_BAD_ARG; 121 } else { 122 *line = cache->lines[chunk_line_id]; 123 } 124 mutex_unlock(cache->mutex); 125 126 return res; 127 } 128 129 void 130 cache_put_chunk 131 (struct cache* cache, 132 const size_t chunk_id, 133 const struct line lines[NLINES_PER_CHUNK]) 134 { 135 ASSERT(cache && chunk_id != CHUNK_ID_NONE && lines); 136 137 mutex_lock(cache->mutex); 138 if(cache->chunk_id != chunk_id) { 139 cache->chunk_id = chunk_id; 140 memcpy(cache->lines, lines, sizeof(struct line)*NLINES_PER_CHUNK); 141 } 142 mutex_unlock(cache->mutex); 143 }