ssize_t action_write_to_fast(void *userdata, request_t *request, f_hash_to_fast callback){ // {{{ ssize_t ret; data_t *r_buffer; data_t *r_size; uintmax_t offset = 0; uintmax_t size = ~0; hash_data_get(ret, TYPE_UINTT, offset, request, HK(offset)); if( (r_size = hash_data_find(request, HK(size))) != NULL){ data_get(ret, TYPE_UINTT, size, r_size); } if( (r_buffer = hash_data_find(request, HK(buffer))) == NULL) return -EINVAL; data_t d_slice = DATA_SLICET(userdata, offset, size); // FIXME fastcall_convert_to r_convert = { { 5, ACTION_CONVERT_TO }, &d_slice, FORMAT(native) }; ret = data_query(r_buffer, &r_convert); fastcall_write r_write = { { 5, ACTION_WRITE }, 0, &r_convert.transfered, sizeof(r_convert.transfered) }; if(r_size) data_query(r_size, &r_write); return ret; } // }}}
ssize_t action_crud_to_fast(void *userdata, request_t *request, f_hash_to_fast callback){ // {{{ ssize_t ret; action_t action; data_t *key; data_t *value; hash_data_get(ret, TYPE_ACTIONT, action, request, HK(action)); if(ret != 0) return ret; key = hash_data_find(request, HK(key)); value = hash_data_find(request, HK(value)); if(key){ data_realholder(ret, key, key); if(ret < 0) return ret; } if(value){ data_realholder(ret, value, value); if(ret < 0) return ret; } fastcall_crud fargs = { { 4, action }, key, value }; ret = callback(userdata, &fargs); return ret; } // }}}
ssize_t action_enum_to_fast(void *userdata, request_t *request, f_hash_to_fast callback){ // {{{ data_t *dest_data; if( (dest_data = hash_data_find(request, HK(data))) == NULL) return -EINVAL; fastcall_enum fargs = { { 4, ACTION_ENUM }, dest_data }; return callback(userdata, &fargs); } // }}}
static ssize_t try_handler(machine_t *machine, request_t *request){ // {{{ ssize_t ret; data_t freeme; request_t *try_request; try_userdata *userdata = (try_userdata *)machine->userdata; try_threaddata *threaddata = thread_data_get(&userdata->thread_data); threaddata->machine = machine; threaddata->request = request; threaddata->ret = 0; data_set_void(&freeme); if(userdata->request == 0){ try_request = request; }else{ if( (ret = get_hash(hash_data_find(request, userdata->request), &freeme, &try_request)) < 0) return ret; } request_t r_next[] = { { userdata->return_to, DATA_MACHINET(userdata->try_end) }, hash_inline(try_request), hash_end }; fastcall_query r_query = { { 3, ACTION_QUERY }, r_next }; if( (ret = data_query(&userdata->machine, &r_query)) < 0){ if(userdata->request == 0){ request_t r_pass[] = { { HK(ret), DATA_PTR_SIZET(&ret) }, hash_inline(request), hash_end }; threaddata->ret = machine_pass(machine, r_pass); }else{ request_t r_pass[] = { { HK(ret), DATA_PTR_SIZET(&ret) }, hash_inline(try_request), hash_end }; request_t r_next[] = { { HK(ret), DATA_PTR_SIZET(&ret) }, { userdata->request_out, DATA_PTR_HASHT(r_pass) }, hash_inline(request), hash_end }; threaddata->ret = machine_pass(machine, r_next); } } data_free(&freeme); return threaddata->ret; } // }}}
ssize_t action_convert_from_to_fast(void *userdata, request_t *request, f_hash_to_fast callback){ // {{{ ssize_t ret; data_t *input; format_t format = FORMAT(native); hash_data_get(ret, TYPE_FORMATT, format, request, HK(format)); if( (input = hash_data_find(request, HK(source))) == NULL) return -EINVAL; fastcall_convert_from fargs = { { 5, ACTION_CONVERT_FROM }, input, format }; ret = callback(userdata, &fargs); data_t *buffer = hash_data_find(request, HK(size)); fastcall_write r_write = { { 5, ACTION_WRITE }, 0, &fargs.transfered, sizeof(fargs.transfered) }; if(buffer) data_query(buffer, &r_write); return ret; } // }}}
static ssize_t allocator_new(allocator_fixed_t **pfdata, hash_t *config){ // {{{ ssize_t ret; data_t *sample; allocator_fixed_t *fdata; if((fdata = calloc(1, sizeof(allocator_fixed_t))) == NULL) return error("calloc failed"); pthread_rwlock_init(&fdata->rwlock, NULL); // get removed items tracker hash_holder_consume(ret, fdata->removed_items, config, HK(removed_items)); hash_holder_consume(ret, fdata->storage, config, HK(storage)); if(ret != 0){ ret = error("invalid storage supplied"); goto error; } hash_data_get(ret, TYPE_UINTT, fdata->item_size, config, HK(item_size)); if(ret != 0){ if( (sample = hash_data_find(config, HK(item_sample))) == NULL){ ret = error("no item_size nor item_sample supplied"); goto error; } fastcall_length r_len = { { 4, ACTION_LENGTH }, 0, FORMAT(binary) }; if( data_query(sample, &r_len) != 0 ){ ret = error("bad item_sample"); goto error; } fdata->item_size = r_len.length; } if(fdata->item_size == 0){ ret = error("bad item size"); goto error; } // get last id fastcall_length r_len = { { 4, ACTION_LENGTH }, 0, FORMAT(clean) }; if( data_query(&fdata->storage, &r_len) != 0){ ret = error("bad underlying storage"); goto error; } fdata->last_id = r_len.length / fdata->item_size; *pfdata = fdata; return 0; error: allocator_destroy(fdata); return ret; } // }}}
ssize_t action_pop_to_fast(void *userdata, request_t *request, f_hash_to_fast callback){ // {{{ ssize_t ret; data_t *pointer; if( (pointer = hash_data_find(request, HK(data))) == NULL) return -EINVAL; data_realholder(ret, pointer, pointer); if(ret < 0) return ret; fastcall_pop fargs = { { 3, ACTION_POP }, pointer }; return callback(userdata, &fargs); } // }}}
ssize_t ipc_shmem_query (ipc_t *ipc, request_t *request){ // {{{ ssize_t ret; uintmax_t f_async = 0; data_t *buffer; ipc_shmem_block *block; ipc_shmem_userdata *userdata = (ipc_shmem_userdata *)ipc->userdata; // check async state switch(userdata->forced_state){ case FORCE_SYNC: break; // already == 0 case FORCE_ASYNC: f_async = 1; break; case FORCE_NONE: hash_data_get(ret, TYPE_UINTT, f_async, request, HK(async)); break; }; buffer = hash_data_find(request, userdata->buffer); // send request if( (block = shmem_get_block(userdata, STATUS_FREE, STATUS_WRITING)) == NULL) return error("strange error"); // write data to ipc memory data_t d_ipcmem = DATA_RAW(userdata->shmdata + block->data_rel_ptr, userdata->shmaddr->item_size); fastcall_convert_to r_convert = { { 4, ACTION_CONVERT_TO }, &d_ipcmem, FORMAT(packed) }; if( (ret = data_query(buffer, &r_convert)) < 0) return error("can not write buffer to ipc memory"); //block->size = r_read.buffer_size; block->return_result = (f_async == 0) ? 1 : 0; if( (ret = shmem_block_status(userdata, block, STATUS_WRITING, STATUS_WRITTEN)) < 0) return ret; if(f_async == 0){ // synchronous request // wait for answer sem_wait(&block->sem_done); // read request back if(userdata->return_result != 0){ fastcall_convert_from r_convert_from = { { 5, ACTION_CONVERT_FROM }, &d_ipcmem, FORMAT(packed) }; data_query(buffer, &r_convert_from); } ret = 0; if(shmem_block_status(userdata, block, STATUS_EXEC_DONE, STATUS_FREE) < 0) return error("strange error 3"); }else{ ret = 0; // success } return ret; } // }}}
static ssize_t stderr_handler(backend_t *backend, request_t *request){ // {{{ ssize_t ret, retd; data_t *input; std_userdata *userdata = (std_userdata *)backend->userdata; if( (input = hash_data_find(request, userdata->key)) == NULL) return error("input key not supplied"); static fastcall_transfer r_transfer = { { 3, ACTION_TRANSFER }, &stderr_io }; ret = data_query(input, &r_transfer); hash_data_set(retd, TYPE_UINTT, r_transfer.transfered, request, HK(size)); return ret; } // }}}
ssize_t action_pack_to_fast(void *userdata, request_t *request, f_hash_to_fast callback){ // {{{ ssize_t ret; action_t action; data_t *input; data_t *output; format_t format = FORMAT(packed); hash_data_get(ret, TYPE_ACTIONT, action, request, HK(action)); if(ret != 0) return ret; hash_data_get(ret, TYPE_FORMATT, format, request, HK(format)); input = hash_data_find(request, HK(input)); output = hash_data_find(request, HK(output)); if(!input || !output) return -EINVAL; data_realholder(ret, input, input); if(ret < 0) return ret; data_realholder(ret, output, output); if(ret < 0) return ret; fastcall_pack fargs = { { 6, action }, input, output, format }; ret = callback(userdata, &fargs); data_t *buffer = hash_data_find(request, HK(size)); fastcall_write r_write = { { 5, ACTION_WRITE }, 0, &fargs.transfered, sizeof(fargs.transfered) }; if(buffer) data_query(buffer, &r_write); return ret; } // }}}
static ssize_t data_env_t_getdata(data_t *data, fastcall_getdata *fargs){ // {{{ request_t *curr_request; env_t *fdata = (env_t *)data->ptr; if(fdata == NULL) return -EINVAL; if( (curr_request = request_get_current()) == NULL) return -EINVAL; if( (fargs->data = hash_data_find(curr_request, fdata->key)) == NULL) return -EINVAL; return 0; } // }}}
static ssize_t data_env_t_handler(data_t *data, fastcall_header *hargs){ // {{{ data_t *real_data; request_t *curr_request; env_t *fdata = (env_t *)data->ptr; if(fdata == NULL) return -EINVAL; if( (curr_request = request_get_current()) == NULL) return -EINVAL; if( (real_data = hash_data_find(curr_request, fdata->key)) == NULL) return -EINVAL; return data_query(real_data, hargs); } // }}}
ssize_t action_length_to_fast(void *userdata, request_t *request, f_hash_to_fast callback){ // {{{ ssize_t ret; format_t format = FORMAT(native); hash_data_get(ret, TYPE_FORMATT, format, request, HK(format)); fastcall_length fargs = { { 4, ACTION_LENGTH }, 0, format }; ret = callback(userdata, &fargs); data_t *buffer = hash_data_find(request, HK(size)); fastcall_write r_write = { { 5, ACTION_WRITE }, 0, &fargs.length, sizeof(fargs.length) }; if(buffer) data_query(buffer, &r_write); return ret; } // }}}
static ssize_t lookup_handler(backend_t *backend, request_t *request){ // {{{ ssize_t ret; data_t *d; data_t d_output; data_t d_void = DATA_VOID; lookup_userdata *userdata = (lookup_userdata *)backend->userdata; if( userdata->force_query != 0 || hash_find(request, userdata->output) == NULL ){ d_output.type = userdata->output_type; fastcall_alloc r_alloc = { { 3, ACTION_ALLOC }, 100 }; if(data_query(&d_output, &r_alloc) < 0) return -ENOMEM; request_t r_query[] = { { HK(action), DATA_UINT32T(ACTION_READ) }, { userdata->output, d_output }, hash_next(request) }; switch( (ret = backend_query(userdata->backend_index, r_query)) ){ case 0: d = hash_data_find(r_query, userdata->output); break; case -ENOENT: d = &d_void; break; default: goto free; }; request_t r_next[] = { { userdata->output, *d }, hash_next(request) }; ret = backend_pass(backend, r_next); free:; fastcall_alloc r_free = { { 2, ACTION_FREE } }; data_query(&d_output, &r_free); return (ret < 0) ? ret : -EEXIST; } return ( (ret = backend_pass(backend, request)) < 0 ) ? ret : -EEXIST; } // }}}
static ssize_t murmur2_64_handler(machine_t *machine, request_t *request){ // {{{ uint64_t hash = 0; data_t *key = NULL; murmur_userdata *userdata = (murmur_userdata *)machine->userdata; key = hash_data_find(request, userdata->input); if(key == NULL){ if(userdata->fatal == 0) return machine_pass(machine, request); return error("input key not supplied"); } hash = MurmurHash64A(key, 0); request_t r_next[] = { { userdata->output, DATA_UINT64T(hash) }, hash_next(request) }; return machine_pass(machine, r_next); } // }}}
static ssize_t struct_machine_pack(machine_t *machine, request_t *request){ ssize_t ret; size_t struct_size; data_t *buffer; request_t *values; struct_userdata *userdata = (struct_userdata *)machine->userdata; switch(userdata->values){ case STRUCT_VALUES_WHOLE: values = request; break; case STRUCT_VALUES_ONE: hash_data_get(ret, TYPE_HASHT, values, request, userdata->key_values); if(ret != 0) return error("hash with keys not supplied"); break; }; if(userdata->lazy == 1){ request_t r_next[] = { { userdata->buffer, DATA_STRUCTT(userdata->structure, values) }, hash_next(request) }; return machine_pass(machine, r_next); }else{ buffer = hash_data_find(request, userdata->buffer); if(buffer != NULL){ if( (struct_size = struct_pack(userdata->structure, values, buffer)) == 0) return error("struct_pack failed"); request_t new_request[] = { { userdata->size, DATA_SIZET(struct_size) }, hash_next(request) }; return machine_pass(machine, new_request); } return machine_pass(machine, request); } }
ssize_t action_push_to_fast(void *userdata, request_t *request, f_hash_to_fast callback){ // {{{ ssize_t ret; data_t *pointer; data_t holder; data_t *holder_ptr = NULL; if( (pointer = hash_data_find(request, HK(data))) != NULL){ data_realholder(ret, pointer, pointer); if(ret < 0) return ret; holder_consume(ret, holder, pointer); if(ret != 0) return -EINVAL; if(holder.type != TYPE_VOIDT) // same as missing HK(data) holder_ptr = &holder; } fastcall_push fargs = { { 3, ACTION_PUSH }, holder_ptr }; return callback(userdata, &fargs); } // }}}
static ssize_t struct_machine_unpack(machine_t *machine, request_t *request){ ssize_t ret; data_t *buffer; request_t *values; struct_userdata *userdata = (struct_userdata *)machine->userdata; buffer = hash_data_find(request, userdata->buffer); if(buffer != NULL){ switch(userdata->values){ case STRUCT_VALUES_WHOLE: values = request; break; case STRUCT_VALUES_ONE: hash_data_get(ret, TYPE_HASHT, values, request, userdata->key_values); if(ret != 0) return error("hash with keys not supplied"); break; }; if(struct_unpack(userdata->structure, values, buffer) == 0) return error("struct_unpack failed"); } return machine_pass(machine, request); }
static ssize_t mphf_handler(backend_t *backend, request_t *request){ // {{{ ssize_t ret; uint32_t action; uintmax_t d_input; uintmax_t *d_output; data_t *data_output; mphf_userdata *userdata = (mphf_userdata *)backend->userdata; hash_data_copy(ret, TYPE_UINT32T, action, request, HK(action)); if(ret != 0) return -ENOSYS; // rebuilds if(action == ACTION_REBUILD){ if( (ret = userdata->mphf_proto->func_rebuild(&userdata->mphf)) < 0) return ret; userdata->broken = 0; return -EBADF; } if(userdata->broken != 0) return -EBADF; // hash_data_copy(ret, TYPE_UINTT, d_input, request, userdata->input); if(ret != 0) return -EINVAL; data_output = hash_data_find(request, userdata->output); if(data_output == NULL) return -EINVAL; d_output = data_output->ptr; switch(action){ case ACTION_CREATE: if( (ret = userdata->mphf_proto->func_insert( &userdata->mphf, d_input, *d_output )) < 0){ if(ret == -EBADF) userdata->broken = 1; return ret; } break; case ACTION_WRITE: if( (ret = userdata->mphf_proto->func_update( &userdata->mphf, d_input, *d_output )) < 0){ if(ret == -EBADF) userdata->broken = 1; return ret; } break; case ACTION_READ: switch( (ret = userdata->mphf_proto->func_query( &userdata->mphf, d_input, d_output ))){ case MPHF_QUERY_NOTFOUND: return -ENOENT; case MPHF_QUERY_FOUND: break; default: return ret; }; break; case ACTION_DELETE: if( (ret = userdata->mphf_proto->func_delete( &userdata->mphf, d_input )) < 0){ if(ret == -EBADF) userdata->broken = 1; return ret; } break; } return 0; } // }}}
static ssize_t file_new(file_t **pfdata, config_t *config){ // {{{ ssize_t ret; file_t *fdata; char filepath[DEF_BUFFER_SIZE]; uintmax_t flags = 0; data_t *cfg_filename; uintmax_t cfg_rdonly = 0; uintmax_t cfg_excl = 0; uintmax_t cfg_creat = 1; uintmax_t cfg_retry = 0; uintmax_t cfg_append = 0; uintmax_t cfg_trunc = 0; uintmax_t cfg_mode = S_IRUSR | S_IWUSR; if( (fdata = calloc(1, sizeof(file_t))) == NULL) return error("calloc returns null"); hash_data_get(ret, TYPE_UINTT, cfg_rdonly, config, HK(readonly)); hash_data_get(ret, TYPE_UINTT, cfg_excl, config, HK(exclusive)); hash_data_get(ret, TYPE_UINTT, cfg_creat, config, HK(create)); hash_data_get(ret, TYPE_UINTT, cfg_mode, config, HK(mode)); hash_data_get(ret, TYPE_UINTT, cfg_retry, config, HK(retry)); hash_data_get(ret, TYPE_UINTT, cfg_append, config, HK(append)); hash_data_get(ret, TYPE_UINTT, cfg_trunc, config, HK(truncate)); hash_data_get(ret, TYPE_UINTT, fdata->temprorary, config, HK(temprorary)); if( (cfg_filename = hash_data_find(config, HK(filename))) == NULL){ ret = error("filename not supplied"); goto error; } retry:; // get filepath fastcall_read r_read = { { 5, ACTION_READ }, 0, filepath, sizeof(filepath) - 1 }; if(data_query(cfg_filename, &r_read) < 0){ ret = error("filename invalid"); goto error; } filepath[r_read.buffer_size] = '\0'; // assign flags flags |= cfg_rdonly == 1 ? O_RDONLY : O_RDWR; flags |= cfg_excl == 1 ? O_EXCL : 0; flags |= cfg_creat == 1 ? O_CREAT : 0; flags |= cfg_append == 1 ? O_APPEND : 0; flags |= cfg_trunc == 1 ? O_TRUNC : 0; #ifdef O_LARGEFILE flags |= O_LARGEFILE; #endif if( (fdata->handle = open(filepath, flags, cfg_mode)) == -1){ if(cfg_retry == 1) goto retry; ret = error("file open() error"); goto error; } if(fdata->temprorary != 0){ fdata->path = strdup(filepath); } *pfdata = fdata; return 0; error: file_destroy(fdata); return ret; } // }}}