#include "chunk_array.h" #include "stdbool.h" #include "stdlib.h" #include #define MAX_CHUNK_SIZE 33554432*2 #define N_BUFFERS 8 int min(int value1, int value2) { if (value1 < value2) return value1; return value2; } int get_mod(chunk_array_t* chunk_array,int init_pos) { int mod; if (chunk_array->total_size - init_pos > chunk_array->chunk_size ) { mod = chunk_array->chunk_size; } else { mod = chunk_array->total_size - init_pos; } return mod; } bool inside_buffer(chunk_array_t* chunk_array,int init_pos, size_t pos) { if (posinit_pos + chunk_array->chunk_size-1) { return false; } return true; } void chunk_array_free(chunk_array_t* chunk_array) { if (chunk_array->mmap_array) munmap(chunk_array->mmap_array, chunk_array->total_size * sizeof(double)); for (int i = 0; i < chunk_array->n_buffers; i++) { buffer_free(chunk_array->buffers[i]); } free(chunk_array->buffers); free(chunk_array); } void buffer_flush(chunk_array_t* chunk_array, buffer_t* buffer) { if (buffer->dirty && chunk_array->mmap_array) { int mod = get_mod(chunk_array, buffer->init_pos); memcpy(&chunk_array->mmap_array[buffer->init_pos], buffer->data, mod * sizeof(double)); buffer->dirty = false; } } void buffer_update(chunk_array_t* chunk_array, buffer_t* buffer, size_t pos) { buffer_flush(chunk_array, buffer); if (chunk_array->mmap_array) { int new_init = pos/chunk_array->chunk_size; buffer->init_pos = new_init * chunk_array->chunk_size; int mod = get_mod(chunk_array, buffer->init_pos); memcpy(buffer->data, &chunk_array->mmap_array[buffer->init_pos], mod * sizeof(double)); } } buffer_t* buffer_create(int size) { buffer_t * buffer = (buffer_t*)malloc(sizeof(buffer_t)); if (buffer == NULL) return NULL; buffer->data = malloc(size * sizeof(double)); if (buffer->data == NULL) { free(buffer); return NULL; } buffer->init_pos = 0; buffer->dirty = false; return buffer; } void buffer_free(buffer_t* buffer) { free(buffer->data); free(buffer); } chunk_array_t* chunk_array_create(char* filename, size_t total_size) { chunk_array_t* chunk_array = (chunk_array_t*)malloc(sizeof(chunk_array_t)); if (chunk_array == NULL) { return NULL; } chunk_array->chunk_size = min(MAX_CHUNK_SIZE, total_size); chunk_array->buffers = malloc(sizeof(buffer_t) * N_BUFFERS); chunk_array->buffers[0] = buffer_create(chunk_array->chunk_size); chunk_array->buffers[0]->init_pos = 0; chunk_array->n_buffers = 1; for (int i = 1; i i*chunk_array->chunk_size) { chunk_array->n_buffers++; chunk_array->buffers[i] = buffer_create(chunk_array->chunk_size); chunk_array->buffers[i]->init_pos = i*chunk_array->chunk_size; } else { break; } } if (chunk_array->chunk_size*chunk_array->n_buffers < total_size) { chunk_array->mmap_array = mmap ( NULL, total_size*sizeof(double), PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0 ); if (chunk_array->mmap_array == NULL) { return NULL; } } chunk_array->filename = filename; chunk_array->total_size = total_size; return chunk_array; } buffer_t* chunk_array_update(chunk_array_t* chunk_array, size_t pos) { buffer_t* buffer = chunk_array->buffers[0]; int distance = abs(buffer->init_pos - pos); for(int i=1; in_buffers; i++) { int new_distance = abs(chunk_array->buffers[i]->init_pos - pos); if (new_distance < distance) { distance = new_distance; buffer = chunk_array->buffers[i]; } } buffer_update(chunk_array, buffer, pos); return buffer; } bool chunk_array_get(chunk_array_t* chunk_array, size_t pos, double *valor) { // full memory if (chunk_array->total_size <= chunk_array->chunk_size) { *valor=chunk_array->buffers[0]->data[pos]; return true; } // mmap buffer_t* buffer = NULL; for (int i = 0; in_buffers; i++) { if (inside_buffer(chunk_array, chunk_array->buffers[i]->init_pos, pos)) { buffer = chunk_array->buffers[i]; } } if (!buffer) { buffer = chunk_array_update(chunk_array, pos); } int real_pos = pos%get_mod(chunk_array, buffer->init_pos); *valor=buffer->data[real_pos]; return true; } bool chunk_array_save(chunk_array_t* chunk_array, size_t pos, double valor) { // full memory if (chunk_array->total_size <= chunk_array->chunk_size) { chunk_array->buffers[0]->data[pos]=valor; chunk_array->buffers[0]->dirty = true; return true; } // mmap buffer_t* buffer = NULL; for (int i = 0; in_buffers; i++) { if (inside_buffer(chunk_array, chunk_array->buffers[i]->init_pos, pos)) { buffer = chunk_array->buffers[i]; } } if (!buffer) { buffer = chunk_array_update(chunk_array, pos); } int real_pos = pos%get_mod(chunk_array, buffer->init_pos); buffer->data[real_pos]=valor; buffer->dirty = true; return true; }