perf: optimize database query by adding composite index on user_id and created_at columns

This commit is contained in:
2025-12-03 14:01:02 +00:00
parent 43103e7120
commit 29c8b6d063
11 changed files with 322 additions and 121 deletions
+24 -7
View File
@@ -25,10 +25,14 @@ RavaMethod_t* rava_methodcache_lookup(MethodCache_t* cache,
MethodCacheEntry_t* entry = &cache->entries[idx];
if (entry->class_hash == class_hash &&
entry->method_hash == method_hash &&
entry->method != NULL) {
return entry->method;
for (int i = 0; i < RAVA_METHOD_CACHE_WAYS; i++) {
MethodCacheSlot_t* slot = &entry->slots[i];
if (slot->class_hash == class_hash &&
slot->method_hash == method_hash &&
slot->method != NULL) {
entry->lru = (uint8_t)i;
return slot->method;
}
}
return NULL;
@@ -45,9 +49,22 @@ void rava_methodcache_insert(MethodCache_t* cache,
uint32_t idx = (class_hash ^ method_hash) & RAVA_METHOD_CACHE_MASK;
MethodCacheEntry_t* entry = &cache->entries[idx];
entry->class_hash = class_hash;
entry->method_hash = method_hash;
entry->method = method;
for (int i = 0; i < RAVA_METHOD_CACHE_WAYS; i++) {
if (entry->slots[i].method == NULL) {
entry->slots[i].class_hash = class_hash;
entry->slots[i].method_hash = method_hash;
entry->slots[i].method = method;
entry->lru = (uint8_t)i;
return;
}
}
int evict = (entry->lru + 1) % RAVA_METHOD_CACHE_WAYS;
entry->slots[evict].class_hash = class_hash;
entry->slots[evict].method_hash = method_hash;
entry->slots[evict].method = method;
entry->lru = (uint8_t)evict;
}
void rava_methodcache_clear(MethodCache_t* cache) {
+6
View File
@@ -7,11 +7,17 @@
#define RAVA_METHOD_CACHE_SIZE 256
#define RAVA_METHOD_CACHE_MASK (RAVA_METHOD_CACHE_SIZE - 1)
#define RAVA_METHOD_CACHE_WAYS 2
typedef struct {
uint32_t class_hash;
uint32_t method_hash;
RavaMethod_t* method;
} MethodCacheSlot_t;
typedef struct {
MethodCacheSlot_t slots[RAVA_METHOD_CACHE_WAYS];
uint8_t lru;
} MethodCacheEntry_t;
typedef struct MethodCache_s {
+134 -76
View File
@@ -51,55 +51,6 @@
#define VALUE_AS_INT_FAST(v) ((v).data.int_val)
#define VALUE_AS_LONG_FAST(v) ((v).data.long_val)
RavaValue_t rava_value_int(int32_t value) {
RavaValue_t val;
val.type = RAVA_VAL_INT;
val.data.int_val = value;
return val;
}
RavaValue_t rava_value_long(int64_t value) {
RavaValue_t val;
val.type = RAVA_VAL_LONG;
val.data.long_val = value;
return val;
}
RavaValue_t rava_value_float(float value) {
RavaValue_t val;
val.type = RAVA_VAL_FLOAT;
val.data.float_val = value;
return val;
}
RavaValue_t rava_value_double(double value) {
RavaValue_t val;
val.type = RAVA_VAL_DOUBLE;
val.data.double_val = value;
return val;
}
RavaValue_t rava_value_boolean(bool value) {
RavaValue_t val;
val.type = RAVA_VAL_BOOLEAN;
val.data.bool_val = value;
return val;
}
RavaValue_t rava_value_null() {
RavaValue_t val;
val.type = RAVA_VAL_NULL;
val.data.object_val = NULL;
return val;
}
RavaValue_t rava_value_array(RavaArray_t *array) {
RavaValue_t val;
val.type = RAVA_VAL_ARRAY;
val.data.array_val = array;
return val;
}
RavaValue_t rava_value_string(const char *str) {
RavaValue_t val;
val.type = RAVA_VAL_STRING;
@@ -235,6 +186,14 @@ size_t rava_array_length(RavaArray_t *array) {
return array->length;
}
static inline uint32_t _rava_field_hash(const char *name) {
uint32_t hash = 5381;
while (*name) {
hash = ((hash << 5) + hash) ^ (uint32_t)*name++;
}
return hash & (RAVA_OBJECT_HASH_SIZE - 1);
}
RavaObject_t* rava_object_create(const char *class_name) {
RavaObject_t *obj = calloc(1, sizeof(RavaObject_t));
if (!obj) return NULL;
@@ -243,6 +202,9 @@ RavaObject_t* rava_object_create(const char *class_name) {
obj->field_names = calloc(obj->field_capacity, sizeof(char*));
obj->field_values = calloc(obj->field_capacity, sizeof(RavaValue_t));
obj->field_count = 0;
for (int i = 0; i < RAVA_OBJECT_HASH_SIZE; i++) {
obj->field_hash[i] = -1;
}
return obj;
}
@@ -259,9 +221,16 @@ void rava_object_destroy(RavaObject_t *obj) {
void rava_object_set_field(RavaObject_t *obj, const char *name, RavaValue_t value) {
if (!obj || !name) return;
uint32_t h = _rava_field_hash(name);
int idx = obj->field_hash[h];
if (idx >= 0 && (size_t)idx < obj->field_count && strcmp(obj->field_names[idx], name) == 0) {
obj->field_values[idx] = value;
return;
}
for (size_t i = 0; i < obj->field_count; i++) {
if (strcmp(obj->field_names[i], name) == 0) {
obj->field_values[i] = value;
obj->field_hash[h] = (int)i;
return;
}
}
@@ -272,25 +241,26 @@ void rava_object_set_field(RavaObject_t *obj, const char *name, RavaValue_t valu
}
obj->field_names[obj->field_count] = strdup(name);
obj->field_values[obj->field_count] = value;
obj->field_hash[h] = (int)obj->field_count;
obj->field_count++;
}
RavaValue_t rava_object_get_field(RavaObject_t *obj, const char *name) {
if (!obj || !name) return rava_value_null();
uint32_t h = _rava_field_hash(name);
int idx = obj->field_hash[h];
if (idx >= 0 && (size_t)idx < obj->field_count && strcmp(obj->field_names[idx], name) == 0) {
return obj->field_values[idx];
}
for (size_t i = 0; i < obj->field_count; i++) {
if (strcmp(obj->field_names[i], name) == 0) {
obj->field_hash[h] = (int)i;
return obj->field_values[i];
}
}
return rava_value_null();
}
RavaValue_t rava_value_object(RavaObject_t *obj) {
RavaValue_t val;
val.type = RAVA_VAL_OBJECT;
val.data.object_val = obj;
return val;
}
int32_t rava_value_as_int(RavaValue_t value) {
switch (value.type) {
@@ -407,12 +377,18 @@ void rava_call_stack_destroy(RavaCallStack_t *stack) {
free(stack);
}
void rava_call_stack_push(RavaCallStack_t *stack, RavaCallFrame_t *frame) {
#define RAVA_MAX_CALL_STACK_DEPTH 10000
bool rava_call_stack_push(RavaCallStack_t *stack, RavaCallFrame_t *frame) {
if (stack->count >= RAVA_MAX_CALL_STACK_DEPTH) {
return false;
}
if (stack->count >= stack->capacity) {
stack->capacity *= 2;
stack->frames = realloc(stack->frames, sizeof(RavaCallFrame_t*) * stack->capacity);
}
stack->frames[stack->count++] = frame;
return true;
}
RavaCallFrame_t* rava_call_stack_pop(RavaCallStack_t *stack) {
@@ -426,11 +402,26 @@ RavaCallFrame_t* rava_call_stack_current(RavaCallStack_t *stack) {
return stack->frames[stack->count - 1];
}
static inline uint32_t _rava_static_hash(const char *class_name, const char *field_name) {
uint32_t hash = 5381;
while (*class_name) {
hash = ((hash << 5) + hash) ^ (uint32_t)*class_name++;
}
hash = ((hash << 5) + hash) ^ '.';
while (*field_name) {
hash = ((hash << 5) + hash) ^ (uint32_t)*field_name++;
}
return hash & (RAVA_STATIC_HASH_SIZE - 1);
}
static RavaStaticFieldTable_t* rava_static_field_table_create() {
RavaStaticFieldTable_t *table = malloc(sizeof(RavaStaticFieldTable_t));
table->capacity = 16;
table->fields = calloc(table->capacity, sizeof(RavaStaticField_t));
table->count = 0;
for (int i = 0; i < RAVA_STATIC_HASH_SIZE; i++) {
table->hash_table[i] = -1;
}
return table;
}
@@ -447,9 +438,17 @@ static void rava_static_field_table_destroy(RavaStaticFieldTable_t *table) {
static RavaValue_t* rava_static_field_table_get(RavaStaticFieldTable_t *table,
const char *class_name,
const char *field_name) {
uint32_t h = _rava_static_hash(class_name, field_name);
int idx = table->hash_table[h];
if (idx >= 0 && (size_t)idx < table->count &&
strcmp(table->fields[idx].class_name, class_name) == 0 &&
strcmp(table->fields[idx].field_name, field_name) == 0) {
return &table->fields[idx].value;
}
for (size_t i = 0; i < table->count; i++) {
if (strcmp(table->fields[i].class_name, class_name) == 0 &&
strcmp(table->fields[i].field_name, field_name) == 0) {
table->hash_table[h] = (int)i;
return &table->fields[i].value;
}
}
@@ -460,11 +459,22 @@ static void rava_static_field_table_set(RavaStaticFieldTable_t *table,
const char *class_name,
const char *field_name,
RavaValue_t value) {
RavaValue_t *existing = rava_static_field_table_get(table, class_name, field_name);
if (existing) {
*existing = value;
uint32_t h = _rava_static_hash(class_name, field_name);
int idx = table->hash_table[h];
if (idx >= 0 && (size_t)idx < table->count &&
strcmp(table->fields[idx].class_name, class_name) == 0 &&
strcmp(table->fields[idx].field_name, field_name) == 0) {
table->fields[idx].value = value;
return;
}
for (size_t i = 0; i < table->count; i++) {
if (strcmp(table->fields[i].class_name, class_name) == 0 &&
strcmp(table->fields[i].field_name, field_name) == 0) {
table->fields[i].value = value;
table->hash_table[h] = (int)i;
return;
}
}
if (table->count >= table->capacity) {
table->capacity *= 2;
@@ -474,28 +484,22 @@ static void rava_static_field_table_set(RavaStaticFieldTable_t *table,
table->fields[table->count].class_name = strdup(class_name);
table->fields[table->count].field_name = strdup(field_name);
table->fields[table->count].value = value;
table->hash_table[h] = (int)table->count;
table->count++;
}
static RavaExceptionStack_t* rava_exception_stack_create() {
RavaExceptionStack_t *stack = calloc(1, sizeof(RavaExceptionStack_t));
stack->capacity = 16;
stack->handlers = calloc(stack->capacity, sizeof(RavaExceptionHandler_t));
stack->count = 0;
return stack;
}
static void rava_exception_stack_destroy(RavaExceptionStack_t *stack) {
if (!stack) return;
free(stack->handlers);
free(stack);
}
static void rava_exception_stack_push(RavaExceptionStack_t *stack, RavaExceptionHandler_t handler) {
if (stack->count >= stack->capacity) {
stack->capacity *= 2;
stack->handlers = realloc(stack->handlers, stack->capacity * sizeof(RavaExceptionHandler_t));
}
if (stack->count >= RAVA_MAX_EXCEPTION_DEPTH) return;
stack->handlers[stack->count++] = handler;
}
@@ -505,6 +509,14 @@ static bool rava_exception_stack_pop(RavaExceptionStack_t *stack, RavaExceptionH
return true;
}
static inline uint32_t _rava_class_hash(const char *name) {
uint32_t hash = 5381;
while (*name) {
hash = ((hash << 5) + hash) ^ (uint32_t)*name++;
}
return hash & (RAVA_CLASS_HASH_SIZE - 1);
}
RavaVM_t* rava_vm_create(RavaProgram_t *program) {
RavaVM_t *vm = calloc(1, sizeof(RavaVM_t));
vm->program = program;
@@ -516,6 +528,15 @@ RavaVM_t* rava_vm_create(RavaProgram_t *program) {
vm->has_exception = false;
vm->exception_value = rava_value_null();
vm->exception_stack = rava_exception_stack_create();
for (size_t i = 0; i < RAVA_CLASS_HASH_SIZE; i++) {
vm->class_hash[i] = -1;
}
for (size_t i = 0; i < program->class_count; i++) {
uint32_t h = _rava_class_hash(program->classes[i]->name);
vm->class_hash[h] = (int)i;
}
return vm;
}
@@ -532,8 +553,16 @@ void rava_vm_destroy(RavaVM_t *vm) {
}
static RavaClass_t* _rava_vm_find_class(RavaVM_t *vm, const char *class_name) {
uint32_t h = _rava_class_hash(class_name);
int idx = vm->class_hash[h];
if (idx >= 0 && (size_t)idx < vm->program->class_count &&
strcmp(vm->program->classes[idx]->name, class_name) == 0) {
return vm->program->classes[idx];
}
for (size_t i = 0; i < vm->program->class_count; i++) {
if (strcmp(vm->program->classes[i]->name, class_name) == 0) {
vm->class_hash[h] = (int)i;
return vm->program->classes[i];
}
}
@@ -722,9 +751,21 @@ static bool _rava_vm_execute_instruction(RavaVM_t *vm, RavaCallFrame_t *frame, R
RavaValue_t b = rava_stack_pop(stack);
RavaValue_t a = rava_stack_pop(stack);
if (a.type == RAVA_VAL_LONG || b.type == RAVA_VAL_LONG) {
rava_stack_push(stack, rava_value_long(rava_value_as_long(a) % rava_value_as_long(b)));
int64_t divisor = rava_value_as_long(b);
if (divisor == 0) {
vm->had_error = true;
vm->error_message = strdup("Division by zero");
return false;
}
rava_stack_push(stack, rava_value_long(rava_value_as_long(a) % divisor));
} else {
rava_stack_push(stack, rava_value_int(rava_value_as_int(a) % rava_value_as_int(b)));
int32_t divisor = rava_value_as_int(b);
if (divisor == 0) {
vm->had_error = true;
vm->error_message = strdup("Division by zero");
return false;
}
rava_stack_push(stack, rava_value_int(rava_value_as_int(a) % divisor));
}
break;
}
@@ -861,7 +902,12 @@ static bool _rava_vm_execute_instruction(RavaVM_t *vm, RavaCallFrame_t *frame, R
new_frame->locals[i] = rava_stack_pop(stack);
}
rava_call_stack_push(vm->call_stack, new_frame);
if (!rava_call_stack_push(vm->call_stack, new_frame)) {
vm->had_error = true;
vm->error_message = strdup("Stack overflow");
rava_call_frame_destroy(new_frame);
return false;
}
while (new_frame->pc < new_frame->method->instructions->count) {
RavaInstruction_t *next_instr = &new_frame->method->instructions->instructions[new_frame->pc];
@@ -920,7 +966,12 @@ static bool _rava_vm_execute_instruction(RavaVM_t *vm, RavaCallFrame_t *frame, R
new_frame->locals[i] = args[i];
}
rava_call_stack_push(vm->call_stack, new_frame);
if (!rava_call_stack_push(vm->call_stack, new_frame)) {
vm->had_error = true;
vm->error_message = strdup("Stack overflow");
rava_call_frame_destroy(new_frame);
return false;
}
while (new_frame->pc < new_frame->method->instructions->count) {
RavaInstruction_t *next_instr = &new_frame->method->instructions->instructions[new_frame->pc];
@@ -973,7 +1024,12 @@ static bool _rava_vm_execute_instruction(RavaVM_t *vm, RavaCallFrame_t *frame, R
new_frame->locals[i] = args[i];
}
rava_call_stack_push(vm->call_stack, new_frame);
if (!rava_call_stack_push(vm->call_stack, new_frame)) {
vm->had_error = true;
vm->error_message = strdup("Stack overflow");
rava_call_frame_destroy(new_frame);
return false;
}
while (new_frame->pc < new_frame->method->instructions->count) {
RavaInstruction_t *next_instr = &new_frame->method->instructions->instructions[new_frame->pc];
@@ -1767,8 +1823,9 @@ op_load_array: {
RavaValue_t idx = STACK_POP(stack);
RavaValue_t arr = STACK_POP(stack);
if (arr.type == RAVA_VAL_ARRAY && arr.data.array_val) {
size_t index = (size_t)rava_value_as_int(idx);
if (index < arr.data.array_val->length) {
int32_t i = rava_value_as_int(idx);
if (i >= 0 && (size_t)i < arr.data.array_val->length) {
size_t index = (size_t)i;
switch (arr.data.array_val->element_type) {
case RAVA_VAL_INT:
STACK_PUSH_INT(stack, ((int32_t*)arr.data.array_val->data)[index]);
@@ -1818,8 +1875,9 @@ op_store_array: {
RavaValue_t idx = STACK_POP(stack);
RavaValue_t arr = STACK_POP(stack);
if (arr.type == RAVA_VAL_ARRAY && arr.data.array_val) {
size_t index = (size_t)rava_value_as_int(idx);
if (index < arr.data.array_val->length) {
int32_t i = rava_value_as_int(idx);
if (i >= 0 && (size_t)i < arr.data.array_val->length) {
size_t index = (size_t)i;
switch (arr.data.array_val->element_type) {
case RAVA_VAL_INT:
((int32_t*)arr.data.array_val->data)[index] = rava_value_as_int(value);
+69 -11
View File
@@ -29,12 +29,15 @@ typedef struct {
typedef struct RavaObject_t RavaObject_t;
typedef struct RavaValue_t RavaValue_t;
#define RAVA_OBJECT_HASH_SIZE 16
struct RavaObject_t {
char *class_name;
char **field_names;
RavaValue_t *field_values;
size_t field_count;
size_t field_capacity;
int field_hash[RAVA_OBJECT_HASH_SIZE];
};
struct RavaValue_t {
@@ -74,6 +77,8 @@ typedef struct {
size_t count;
} RavaCallStack_t;
#define RAVA_STATIC_HASH_SIZE 64
typedef struct {
char *class_name;
char *field_name;
@@ -84,6 +89,7 @@ typedef struct {
RavaStaticField_t *fields;
size_t count;
size_t capacity;
int hash_table[RAVA_STATIC_HASH_SIZE];
} RavaStaticFieldTable_t;
struct MethodCache_s;
@@ -96,12 +102,15 @@ typedef struct {
size_t stack_depth;
} RavaExceptionHandler_t;
#define RAVA_MAX_EXCEPTION_DEPTH 64
typedef struct {
RavaExceptionHandler_t *handlers;
RavaExceptionHandler_t handlers[RAVA_MAX_EXCEPTION_DEPTH];
size_t count;
size_t capacity;
} RavaExceptionStack_t;
#define RAVA_CLASS_HASH_SIZE 32
typedef struct {
RavaProgram_t *program;
RavaCallStack_t *call_stack;
@@ -112,15 +121,65 @@ typedef struct {
bool has_exception;
RavaValue_t exception_value;
RavaExceptionStack_t *exception_stack;
int class_hash[RAVA_CLASS_HASH_SIZE];
} RavaVM_t;
RavaValue_t rava_value_int(int32_t value);
RavaValue_t rava_value_long(int64_t value);
RavaValue_t rava_value_float(float value);
RavaValue_t rava_value_double(double value);
RavaValue_t rava_value_boolean(bool value);
RavaValue_t rava_value_null();
RavaValue_t rava_value_array(RavaArray_t *array);
static inline RavaValue_t rava_value_int(int32_t value) {
RavaValue_t val;
val.type = RAVA_VAL_INT;
val.data.int_val = value;
return val;
}
static inline RavaValue_t rava_value_long(int64_t value) {
RavaValue_t val;
val.type = RAVA_VAL_LONG;
val.data.long_val = value;
return val;
}
static inline RavaValue_t rava_value_float(float value) {
RavaValue_t val;
val.type = RAVA_VAL_FLOAT;
val.data.float_val = value;
return val;
}
static inline RavaValue_t rava_value_double(double value) {
RavaValue_t val;
val.type = RAVA_VAL_DOUBLE;
val.data.double_val = value;
return val;
}
static inline RavaValue_t rava_value_boolean(bool value) {
RavaValue_t val;
val.type = RAVA_VAL_BOOLEAN;
val.data.bool_val = value;
return val;
}
static inline RavaValue_t rava_value_null(void) {
RavaValue_t val;
val.type = RAVA_VAL_NULL;
val.data.object_val = NULL;
return val;
}
static inline RavaValue_t rava_value_array(RavaArray_t *array) {
RavaValue_t val;
val.type = RAVA_VAL_ARRAY;
val.data.array_val = array;
return val;
}
static inline RavaValue_t rava_value_object(RavaObject_t *obj) {
RavaValue_t val;
val.type = RAVA_VAL_OBJECT;
val.data.object_val = obj;
return val;
}
RavaValue_t rava_value_string(const char *str);
int32_t rava_value_as_int(RavaValue_t value);
@@ -141,7 +200,6 @@ RavaObject_t* rava_object_create(const char *class_name);
void rava_object_destroy(RavaObject_t *obj);
void rava_object_set_field(RavaObject_t *obj, const char *name, RavaValue_t value);
RavaValue_t rava_object_get_field(RavaObject_t *obj, const char *name);
RavaValue_t rava_value_object(RavaObject_t *obj);
RavaStack_t* rava_stack_create(size_t capacity);
void rava_stack_destroy(RavaStack_t *stack);
@@ -155,7 +213,7 @@ void rava_call_frame_destroy(RavaCallFrame_t *frame);
RavaCallStack_t* rava_call_stack_create();
void rava_call_stack_destroy(RavaCallStack_t *stack);
void rava_call_stack_push(RavaCallStack_t *stack, RavaCallFrame_t *frame);
bool rava_call_stack_push(RavaCallStack_t *stack, RavaCallFrame_t *frame);
RavaCallFrame_t* rava_call_stack_pop(RavaCallStack_t *stack);
RavaCallFrame_t* rava_call_stack_current(RavaCallStack_t *stack);