1 #include "cache.h"
2 #include "util.h"
3 #include "rabs.h"
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <string.h>
7 #include <gc/gc.h>
8 #include <sys/stat.h>
9 #include <targetcache.h>
10 #include <radb.h>
11
12 #define new(T) ((T *)GC_MALLOC(sizeof(T)))
13
14 static string_store_t *MetadataStore;
15 static string_index_t *TargetsIndex;
16 static fixed_store_t *DetailsStore;
17 static string_store_t *DependsStore;
18 static string_store_t *ScansStore;
19 static string_store_t *ExprsStore;
20
21 int CurrentIteration = 0;
22
23 enum {
24 CURRENT_VERSION_INDEX,
25 CURRENT_ITERATION_INDEX,
26 METADATA_SIZE
27 };
28
29 typedef struct cache_details_t {
30 uint8_t Hash[SHA256_BLOCK_SIZE];
31 uint8_t BuildHash[SHA256_BLOCK_SIZE];
32 uint32_t Parent;
33 uint32_t LastUpdated;
34 uint32_t LastChecked;
35 time_t FileTime;
36 } cache_details_t;
37
cache_open(const char * RootPath)38 void cache_open(const char *RootPath) {
39 const char *CacheFileName = concat(RootPath, "/", SystemName, ".db", NULL);
40 struct stat Stat[1];
41 if (stat(CacheFileName, Stat)) {
42 mkdir(CacheFileName, 0777);
43 MetadataStore = string_store_create(concat(CacheFileName, "/metadata", NULL), 16, 0);
44 TargetsIndex = string_index_create(concat(CacheFileName, "/targets", NULL), 32, 4096);
45 DetailsStore = fixed_store_create(concat(CacheFileName, "/details", NULL), sizeof(cache_details_t), 1024);
46 DependsStore = string_store_create(concat(CacheFileName, "/depends", NULL), 32, 4096);
47 ScansStore = string_store_create(concat(CacheFileName, "/scans", NULL), 128, 524288);
48 ExprsStore = string_store_create(concat(CacheFileName, "/exprs", NULL), 16, 512);
49 } else if (!S_ISDIR(Stat->st_mode)) {
50 printf("Version error: database was built with an older version of Rabs. Delete %s to force a clean build.\n", CacheFileName);
51 exit(1);
52 } else {
53 MetadataStore = string_store_open(concat(CacheFileName, "/metadata", NULL));
54 {
55 char Temp[16];
56 string_store_get(MetadataStore, CURRENT_VERSION_INDEX, Temp, 16);
57 int Current[3], Working[3] = {WORKING_VERSION};
58 sscanf(Temp, "%d.%d.%d", Current + 0, Current + 1, Current + 2);
59 if (Current[0] < Working[0]) {
60 printf("Version error: database was built with an older version of Rabs. Delete %s to force a clean build.\n", CacheFileName);
61 exit(1);
62 } else if (Current[0] == Working[0]) {
63 if (Current[1] < Working[1]) {
64 printf("Version error: database was built with an older version of Rabs. Delete %s to force a clean build.\n", CacheFileName);
65 exit(1);
66 } else if (Current[1] == Working[1]) {
67 if (Current[2] < Working[2]) {
68 printf("Version error: database was built with an older version of Rabs. Delete %s to force a clean build.\n", CacheFileName);
69 exit(1);
70 }
71 }
72 }
73 }
74 TargetsIndex = string_index_open(concat(CacheFileName, "/targets", NULL));
75 DetailsStore = fixed_store_open(concat(CacheFileName, "/details", NULL));
76 DependsStore = string_store_open(concat(CacheFileName, "/depends", NULL));
77 ScansStore = string_store_open(concat(CacheFileName, "/scans", NULL));
78 ExprsStore = string_store_open(concat(CacheFileName, "/exprs", NULL));
79 {
80 uint32_t Temp;
81 string_store_get(MetadataStore, CURRENT_ITERATION_INDEX, &Temp, 4);
82 CurrentIteration = Temp;
83 }
84 }
85 ++CurrentIteration;
86 printf("Rabs version = %d.%d.%d\n", CURRENT_VERSION);
87 printf("Build iteration = %d\n", CurrentIteration);
88 {
89 uint32_t Temp = CurrentIteration;
90 string_store_set(MetadataStore, CURRENT_ITERATION_INDEX, &Temp, sizeof(uint32_t));
91 }
92 {
93 char Temp[16];
94 sprintf(Temp, "%d.%d.%d", CURRENT_VERSION);
95 string_store_set(MetadataStore, CURRENT_VERSION_INDEX, Temp, sizeof(Temp));
96 }
97 targetcache_init();
98 atexit(cache_close);
99 }
100
cache_close()101 void cache_close() {
102 string_store_close(MetadataStore);
103 string_index_close(TargetsIndex);
104 fixed_store_close(DetailsStore);
105 string_store_close(DependsStore);
106 string_store_close(ScansStore);
107 string_store_close(ExprsStore);
108 }
109
cache_bump_iteration()110 void cache_bump_iteration() {
111 ++CurrentIteration;
112 printf("Rabs version = %d.%d.%d\n", CURRENT_VERSION);
113 printf("Build iteration = %d\n", CurrentIteration);
114 {
115 uint32_t Temp = CurrentIteration;
116 string_store_set(MetadataStore, CURRENT_ITERATION_INDEX, &Temp, sizeof(uint32_t));
117 }
118 {
119 char Temp[16];
120 sprintf(Temp, "%d.%d.%d", CURRENT_VERSION);
121 string_store_set(MetadataStore, CURRENT_VERSION_INDEX, Temp, sizeof(Temp));
122 }
123 }
124
cache_hash_get(target_t * Target,int * LastUpdated,int * LastChecked,time_t * FileTime,unsigned char Hash[SHA256_BLOCK_SIZE])125 void cache_hash_get(target_t *Target, int *LastUpdated, int *LastChecked, time_t *FileTime, unsigned char Hash[SHA256_BLOCK_SIZE]) {
126 cache_details_t *Details = fixed_store_get(DetailsStore, Target->CacheIndex);
127 memcpy(Hash, Details->Hash, SHA256_BLOCK_SIZE);
128 *LastUpdated = Details->LastUpdated;
129 *LastChecked = Details->LastChecked;
130 *FileTime = Details->FileTime;
131 }
132
cache_hash_set(target_t * Target,time_t FileTime)133 void cache_hash_set(target_t *Target, time_t FileTime) {
134 cache_details_t *Details = fixed_store_get(DetailsStore, Target->CacheIndex);
135 memcpy(Details->Hash, Target->Hash, SHA256_BLOCK_SIZE);
136 Details->LastUpdated = Target->LastUpdated;
137 Details->LastChecked = CurrentIteration;
138 Details->FileTime = FileTime;
139 }
140
cache_build_hash_get(target_t * Target,unsigned char Hash[SHA256_BLOCK_SIZE])141 void cache_build_hash_get(target_t *Target, unsigned char Hash[SHA256_BLOCK_SIZE]) {
142 cache_details_t *Details = fixed_store_get(DetailsStore, Target->CacheIndex);
143 memcpy(Hash, Details->BuildHash, SHA256_BLOCK_SIZE);
144 }
145
cache_build_hash_set(target_t * Target,unsigned char Hash[SHA256_BLOCK_SIZE])146 void cache_build_hash_set(target_t *Target, unsigned char Hash[SHA256_BLOCK_SIZE]) {
147 cache_details_t *Details = fixed_store_get(DetailsStore, Target->CacheIndex);
148 memcpy(Details->BuildHash, Hash, SHA256_BLOCK_SIZE);
149 if (Target->Parent) Details->Parent = Target->Parent->CacheIndex;
150 }
151
cache_last_check_set(target_t * Target,time_t FileTime)152 void cache_last_check_set(target_t *Target, time_t FileTime) {
153 cache_details_t *Details = fixed_store_get(DetailsStore, Target->CacheIndex);
154 Details->LastUpdated = Target->LastUpdated;
155 Details->LastChecked = CurrentIteration;
156 Details->FileTime = FileTime;
157 }
158
cache_parent_get(target_t * Target)159 target_t *cache_parent_get(target_t *Target) {
160 cache_details_t *Details = fixed_store_get(DetailsStore, Target->CacheIndex);
161 size_t Parent = Details->Parent;
162 if (!Parent) return NULL;
163 target_id_slot R = targetcache_index(Parent);
164 return R.Slot[0] ?: target_load(R.Id, Parent, R.Slot);
165 }
166
cache_target_set_parse(uint32_t * Indices)167 static targetset_t *cache_target_set_parse(uint32_t *Indices) {
168 targetset_t *Set = targetset_new();
169 if (!Indices) return Set;
170 int Size = Indices[0];
171 targetset_init(Set, Size);
172 while (--Size >= 0) {
173 size_t Index = *++Indices;
174 target_id_slot R = targetcache_index(Index);
175 target_t *Target = R.Slot[0] ?: target_load(R.Id, Index, R.Slot);
176 targetset_insert(Set, Target);
177 }
178 return Set;
179 }
180
cache_target_set_index(target_t * Target,uint32_t ** IndexP)181 static int cache_target_set_index(target_t *Target, uint32_t **IndexP) {
182 **IndexP = Target->CacheIndex;
183 ++*IndexP;
184 return 0;
185 }
186
cache_depends_get(target_t * Target)187 targetset_t *cache_depends_get(target_t *Target) {
188 size_t Length = string_store_size(DependsStore, Target->CacheIndex);
189 if (Length) {
190 uint32_t *Buffer = GC_MALLOC_ATOMIC(Length);
191 string_store_get(DependsStore, Target->CacheIndex, Buffer, Length);
192 return cache_target_set_parse(Buffer);
193 } else {
194 return targetset_new();
195 }
196 }
197
cache_depends_set(target_t * Target,targetset_t * Depends)198 void cache_depends_set(target_t *Target, targetset_t *Depends) {
199 int Size = Depends->Size - Depends->Space;
200 uint32_t *Indices = anew(uint32_t, Size + 1);
201 Indices[0] = Size;
202 uint32_t *IndexP = Indices + 1;
203 targetset_foreach(Depends, &IndexP, (void *)cache_target_set_index);
204 string_store_set(DependsStore, Target->CacheIndex, Indices, (Size + 1) * sizeof(uint32_t));
205 }
206
cache_scan_get(target_t * Target)207 targetset_t *cache_scan_get(target_t *Target) {
208 size_t Length = string_store_size(ScansStore, Target->CacheIndex);
209 if (Length) {
210 uint32_t *Buffer = GC_MALLOC_ATOMIC(Length);
211 string_store_get(ScansStore, Target->CacheIndex, Buffer, Length);
212 return cache_target_set_parse(Buffer);
213 } else {
214 return targetset_new();
215 }
216 }
217
cache_scan_set(target_t * Target,targetset_t * Scans)218 void cache_scan_set(target_t *Target, targetset_t *Scans) {
219 int Size = Scans->Size - Scans->Space;
220 uint32_t *Indices = anew(uint32_t, Size + 1);
221 Indices[0] = Size;
222 uint32_t *IndexP = Indices + 1;
223 targetset_foreach(Scans, &IndexP, (void *)cache_target_set_index);
224 string_store_set(ScansStore, Target->CacheIndex, Indices, (Size + 1) * sizeof(uint32_t));
225 }
226
cache_expr_value_size(ml_value_t * Value)227 static int cache_expr_value_size(ml_value_t *Value) {
228 if (Value->Type == MLStringT) {
229 return 6 + ml_string_length(Value);
230 } else if (Value->Type == MLIntegerT) {
231 return 9;
232 } else if (Value->Type == MLRealT) {
233 return 9;
234 } else if (Value == MLNil) {
235 return 1;
236 } else if (Value->Type == MLListT) {
237 int Size = 5;
238 ML_LIST_FOREACH(Value, Node) {
239 Size += cache_expr_value_size(Node->Value);
240 }
241 return Size;
242 } else if (Value->Type == MLMapT) {
243 int Size = 5;
244 ML_MAP_FOREACH(Value, Node) {
245 Size += cache_expr_value_size(Node->Key);
246 Size += cache_expr_value_size(Node->Value);
247 }
248 return Size;
249 } else if (ml_is(Value, TargetT)) {
250 target_t *Target = (target_t *)Value;
251 return 6 + Target->IdLength;
252 }
253 return 0;
254 }
255
256 #define CACHE_EXPR_NIL 0
257 #define CACHE_EXPR_STRING 1
258 #define CACHE_EXPR_INTEGER 2
259 #define CACHE_EXPR_REAL 3
260 #define CACHE_EXPR_LIST 4
261 #define CACHE_EXPR_MAP 5
262 #define CACHE_EXPR_TARGET 6
263
cache_expr_value_write(ml_value_t * Value,char * Buffer)264 static char *cache_expr_value_write(ml_value_t *Value, char *Buffer) {
265 if (Value->Type == MLStringT) {
266 int Length = ml_string_length(Value);
267 *Buffer++ = CACHE_EXPR_STRING;
268 *(int32_t *)Buffer = Length;
269 Buffer += 4;
270 memcpy(Buffer, ml_string_value(Value), Length);
271 Buffer[Length] = 0;
272 Buffer += Length + 1;
273 } else if (Value->Type == MLIntegerT) {
274 *Buffer++ = CACHE_EXPR_INTEGER;
275 *(int64_t *)Buffer = ml_integer_value(Value);
276 Buffer += 8;
277 } else if (Value->Type == MLRealT) {
278 *Buffer++ = CACHE_EXPR_REAL;
279 *(double *)Buffer = ml_real_value(Value);
280 Buffer += 8;
281 } else if (Value == MLNil) {
282 *Buffer++ = CACHE_EXPR_NIL;
283 } else if (Value->Type == MLListT) {
284 *Buffer++ = CACHE_EXPR_LIST;
285 *(int32_t *)Buffer = ml_list_length(Value);
286 Buffer += 4;
287 ML_LIST_FOREACH(Value, Node) {
288 Buffer = cache_expr_value_write(Node->Value, Buffer);
289 }
290 } else if (Value->Type == MLMapT) {
291 *Buffer++ = CACHE_EXPR_MAP;
292 *(int32_t *)Buffer = ml_map_size(Value);
293 Buffer += 4;
294 ML_MAP_FOREACH(Value, Node) {
295 Buffer = cache_expr_value_write(Node->Key, Buffer);
296 Buffer = cache_expr_value_write(Node->Value, Buffer);
297 }
298 } else if (ml_is(Value, TargetT)) {
299 *Buffer++ = CACHE_EXPR_TARGET;
300 target_t *Target = (target_t *)Value;
301 *(int32_t *)Buffer = Target->IdLength;
302 memcpy(Buffer, Target->Id, Target->IdLength);
303 Buffer[Target->IdLength] = 0;
304 Buffer += Target->IdLength + 1;
305 }
306 return Buffer;
307 }
308
cache_expr_value_read(const char * Buffer,ml_value_t ** Output)309 static const char *cache_expr_value_read(const char *Buffer, ml_value_t **Output) {
310 switch (*Buffer++) {
311 case CACHE_EXPR_NIL: {
312 *Output = MLNil;
313 return Buffer;
314 }
315 case CACHE_EXPR_STRING: {
316 int Length = *(int32_t *)Buffer;
317 Buffer += 4;
318 char *Chars = GC_MALLOC_ATOMIC(Length + 1);
319 memcpy(Chars, Buffer, Length);
320 Chars[Length] = 0;
321 *Output = ml_string(Chars, Length);
322 return Buffer + Length + 1;
323 }
324 case CACHE_EXPR_INTEGER: {
325 *Output = ml_integer(*(int64_t *)Buffer);
326 return Buffer + 8;
327 }
328 case CACHE_EXPR_REAL: {
329 *Output = ml_real(*(double *)Buffer);
330 return Buffer + 8;
331 }
332 case CACHE_EXPR_LIST: {
333 int Length = *(int32_t *)Buffer;
334 Buffer += 4;
335 ml_value_t *List = *Output = ml_list();
336 for (int I = 0; I < Length; ++I) {
337 ml_value_t *Value;
338 Buffer = cache_expr_value_read(Buffer, &Value);
339 ml_list_append(List, Value);
340 }
341 return Buffer;
342 }
343 case CACHE_EXPR_MAP: {
344 int Length = *(int32_t *)Buffer;
345 Buffer += 4;
346 ml_value_t *Map = *Output = ml_map();
347 for (int I = 0; I < Length; ++I) {
348 ml_value_t *Key, *Value;
349 Buffer = cache_expr_value_read(Buffer, &Key);
350 Buffer = cache_expr_value_read(Buffer, &Value);
351 ml_map_insert(Map, Key, Value);
352 }
353 return Buffer;
354 }
355 case CACHE_EXPR_TARGET: {
356 int Length = *(int32_t *)Buffer;
357 Buffer += 4;
358 target_t *Target = target_find(Buffer);
359 if (!Target) {
360 printf("\e[31mError: target not defined: %s\e[0m\n", Buffer);
361 exit(1);
362 }
363 *Output = (ml_value_t *)Target;
364 return Buffer + Length + 1;
365 }
366 }
367 return Buffer;
368 }
369
cache_expr_get(target_t * Target)370 ml_value_t *cache_expr_get(target_t *Target) {
371 ml_value_t *Result = 0;
372 size_t Length = string_store_size(ExprsStore, Target->CacheIndex);
373 if (Length) {
374 char *Buffer = GC_MALLOC_ATOMIC(Length);
375 string_store_get(ExprsStore, Target->CacheIndex, Buffer, Length);
376 cache_expr_value_read(Buffer, &Result);
377 }
378 return Result;
379 }
380
cache_expr_set(target_t * Target,ml_value_t * Value)381 void cache_expr_set(target_t *Target, ml_value_t *Value) {
382 size_t Length = cache_expr_value_size(Value);
383 char *Buffer = GC_MALLOC_ATOMIC(Length);
384 cache_expr_value_write(Value, Buffer);
385 string_store_set(ExprsStore, Target->CacheIndex, Buffer, Length);
386 }
387
cache_target_id_to_index(const char * Id)388 size_t cache_target_id_to_index(const char *Id) {
389 string_index_result_t Result = string_index_insert2(TargetsIndex, Id, 0);
390 if (Result.Created) {
391 cache_details_t *Details = fixed_store_get(DetailsStore, Result.Index);
392 memset(Details, 0, sizeof(cache_details_t));
393 }
394 return Result.Index;
395 }
396
cache_target_id_to_index_existing(const char * Id)397 size_t cache_target_id_to_index_existing(const char *Id) {
398 return string_index_search(TargetsIndex, Id, 0);
399 }
400
cache_target_index_to_id(size_t Index)401 const char *cache_target_index_to_id(size_t Index) {
402 size_t Size = string_index_size(TargetsIndex, Index);
403 char *Id = GC_MALLOC_ATOMIC(Size + 1);
404 string_index_get(TargetsIndex, Index, Id, Size);
405 Id[Size] = 0;
406 return Id;
407 }
408
cache_target_count()409 size_t cache_target_count() {
410 return string_index_count(TargetsIndex);
411 }
412