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