extern void fc_solve_dbm_store_offload_pre_cache( fcs_dbm_store store, fcs_pre_cache *const pre_cache) { fcs_dbm *const db = (fcs_dbm *)store; dict_t *const kaz_tree = pre_cache->kaz_tree; DB *const dbp = db->dbp; for (dnode_t *node = fc_solve_kaz_tree_first(kaz_tree); node; node = fc_solve_kaz_tree_next(kaz_tree, node)) { const_AUTO(kv, (pre_cache_key_val_pair *)(node->dict_key)); db->key.data = kv->key.s + 1; db->key.size = kv->key.s[0]; db->data.data = kv->parent.s + 1; db->data.size = kv->parent.s[0]; int ret; if ((ret = dbp->put(dbp, NULL, &(db->key), &(db->data), 0)) != 0) { dbp->err(dbp, ret, "DB->put"); my_close(dbp, ret); } } }
static inline void instance_check_key(fcs_dbm_solver_thread_t *const thread, fcs_dbm_solver_instance_t *const instance, const int key_depth, fcs_encoded_state_buffer_t *const key, fcs_dbm_record_t *const parent, const unsigned char move GCC_UNUSED, const fcs_which_moves_bitmask_t *const which_irreversible_moves_bitmask #ifdef FCS_DBM_CACHE_ONLY , const fcs_fcc_move_t *moves_to_parent #endif ) { #ifdef DEBUG_OUT fcs_state_locs_struct_t locs; fc_solve_init_locs(&locs); const_AUTO(local_variant, instance->common.variant); #endif const_AUTO(coll, &(instance->coll)); { #ifdef FCS_DBM_WITHOUT_CACHES fcs_dbm_record_t *token; #else fcs_dbm_record_t *token = key; #endif #ifndef FCS_DBM_WITHOUT_CACHES if (cache_does_key_exist(&(coll->cache_store.cache), key)) { return; } #ifndef FCS_DBM_CACHE_ONLY else if (pre_cache_does_key_exist(&(coll->cache_store.pre_cache), key)) { return; } #endif #ifndef FCS_DBM_CACHE_ONLY else if (fc_solve_dbm_store_does_key_exist( coll->cache_store.store, key->s)) { cache_insert(&(coll->cache_store.cache), key, NULL, '\0'); return; } #endif else #else if ((token = fc_solve_dbm_store_insert_key_value( coll->cache_store.store, key, parent, TRUE))) #endif { #ifdef FCS_DBM_CACHE_ONLY fcs_cache_key_info_t *cache_key; #endif #ifndef FCS_DBM_WITHOUT_CACHES #ifndef FCS_DBM_CACHE_ONLY pre_cache_insert(&(coll->cache_store.pre_cache), key, parent); #else cache_key = cache_insert( &(coll->cache_store.cache), key, moves_to_parent, move); #endif #endif if (key_depth == instance->curr_depth) { /* Now insert it into the queue. */ fcs_lock_lock(&instance->global_lock); fcs_depth_multi_queue__insert( &(coll->depth_queue), thread->state_depth + 1, #ifdef FCS_DBM_WITHOUT_CACHES (const fcs_offloading_queue_item_t *)(&token) #else key #endif ); instance->common.count_of_items_in_queue++; instance->common.num_states_in_collection++; instance_debug_out_state(instance, &(token->key)); fcs_lock_unlock(&instance->global_lock); } else { /* Handle an irreversible move */ /* Calculate the new fingerprint to which the exit * point belongs. */ fcs_which_moves_bitmask_t new_fingerprint = {{'\0'}}; for (size_t i = 0; i < COUNT(new_fingerprint.s); i++) { new_fingerprint.s[i] = which_irreversible_moves_bitmask->s[i] + instance->fingerprint_which_irreversible_moves_bitmask .s[i]; } int trace_num; fcs_encoded_state_buffer_t *trace; fcs_lock_lock(&instance->fcc_exit_points_output_lock); /* instance->storage_lock is already locked * in instance_check_multiple_keys and we should not * lock it here. */ calc_trace(token, &trace, &trace_num); { FccEntryPointNode fcc_entry_key; fcc_entry_key.kv.key.key = trace[trace_num - 1]; FccEntryPointNode *val_proto = RB_FIND(FccEntryPointList, &(instance->fcc_entry_points), &fcc_entry_key); const long location_in_file = val_proto->kv.val.location_in_file; fseek(instance->fingerprint_fh, location_in_file, SEEK_SET); #ifdef HAVE_GETLINE getline(&(instance->fingerprint_line), &(instance->fingerprint_line_size), instance->fingerprint_fh); #else fgets(instance->fingerprint_line, instance->fingerprint_line_size, instance->fingerprint_fh); #endif char *const moves_to_state_enc = strchr( strchr(instance->fingerprint_line, ' ') + 1, ' ') + 1; char *const trailing_newline = strchr(moves_to_state_enc, '\n'); if (trailing_newline) { *trailing_newline = '\0'; } const size_t string_len = strlen(moves_to_state_enc); instance_alloc_num_moves( instance, ((string_len * 3) >> 2) + 20); base64_decode(moves_to_state_enc, string_len, ((unsigned char *)instance->moves_to_state), &(instance->moves_to_state_len)); } const_SLOT(moves_to_state_len, instance); const size_t added_moves_to_output = moves_to_state_len + trace_num - 1; instance_alloc_num_moves(instance, added_moves_to_output); unsigned char *const moves_to_state = instance->moves_to_state; for (int i = trace_num - 1; i > 0; i--) { moves_to_state[moves_to_state_len + trace_num - 1 - i] = get_move_from_parent_to_child(instance, &(thread->delta_stater), trace[i], trace[i - 1]); } const size_t new_max_enc_len = ((added_moves_to_output * 4) / 3) + 20; if (new_max_enc_len > instance->moves_base64_encoding_buffer_max_len) { instance->moves_base64_encoding_buffer = SREALLOC(instance->moves_base64_encoding_buffer, new_max_enc_len); instance->moves_base64_encoding_buffer_max_len = new_max_enc_len; } size_t unused_output_len; base64_encode(moves_to_state, added_moves_to_output, instance->moves_base64_encoding_buffer, &unused_output_len); char fingerprint_base64[100]; char state_base64[100]; base64_encode(new_fingerprint.s, sizeof(new_fingerprint), fingerprint_base64, &unused_output_len); base64_encode((unsigned char *)&(*key), sizeof(*key), state_base64, &unused_output_len); /* Output the exit point. */ fprintf(instance->fcc_exit_points_out_fh, "%s %s %zd %s\n", fingerprint_base64, state_base64, added_moves_to_output, instance->moves_base64_encoding_buffer); #ifdef DEBUG_OUT { fcs_state_keyval_pair_t state; DECLARE_IND_BUF_T(indirect_stacks_buffer) fc_solve_delta_stater_decode_into_state( &(thread->delta_stater), key->s, &state, indirect_stacks_buffer); char state_str[2000]; FCS__RENDER_STATE(state_str, &(state.s), &locs); fprintf(stderr, "Check Key: <<<\n%s\n>>>\n\n[%s %s %ld %s]\n\n", state_str, fingerprint_base64, state_base64, added_moves_to_output, instance->moves_base64_encoding_buffer); } #endif fflush(instance->fcc_exit_points_out_fh); fcs_lock_unlock(&instance->fcc_exit_points_output_lock); free(trace); } } }
static void *instance_run_solver_thread(void *const void_arg) { fcs_dbm_queue_item_t physical_item; fcs_dbm_record_t *token = NULL; fcs_dbm_queue_item_t *item, *prev_item; fcs_derived_state_t *derived_list, *derived_list_recycle_bin, *derived_iter; fcs_compact_allocator_t derived_list_allocator; fcs_state_keyval_pair_t state; char *base64_encoding_buffer = NULL; #if 0 size_t base64_encoding_buffer_max_len = 0; #endif #ifdef DEBUG_OUT fcs_state_locs_struct_t locs; fc_solve_init_locs(&locs); #endif DECLARE_IND_BUF_T(indirect_stacks_buffer) const_AUTO(thread, ((thread_arg_t *)void_arg)->thread); const_SLOT(instance, thread); const_AUTO(delta_stater, &(thread->delta_stater)); const_AUTO(local_variant, instance->common.variant); prev_item = item = NULL; int queue_num_extracted_and_processed = 0; fc_solve_compact_allocator_init( &(derived_list_allocator), &(thread->thread_meta_alloc)); derived_list_recycle_bin = NULL; derived_list = NULL; FILE *const out_fh = instance->common.out_fh; TRACE("%s\n", "instance_run_solver_thread start"); const_AUTO(coll, &(instance->coll)); #if 0 fcs_bool_t was_start_key_reachable = instance->was_start_key_reachable; #endif while (1) { /* First of all extract an item. */ fcs_lock_lock(&instance->global_lock); if (prev_item) { instance->common.queue_num_extracted_and_processed--; } if (instance->common.should_terminate == DONT_TERMINATE) { if (fcs_depth_multi_queue__extract(&(coll->depth_queue), &(thread->state_depth), (fcs_offloading_queue_item_t *)(&token))) { physical_item.key = token->key; item = &physical_item; instance_increment(instance); } else { item = NULL; } queue_num_extracted_and_processed = instance->common.queue_num_extracted_and_processed; } fcs_lock_unlock(&instance->global_lock); if ((instance->common.should_terminate != DONT_TERMINATE) || (!queue_num_extracted_and_processed)) { break; } if (!item) { /* Sleep until more items become available in the * queue. */ usleep(5000); } else { /* Handle item. */ fc_solve_delta_stater_decode_into_state( delta_stater, item->key.s, &state, indirect_stacks_buffer); /* A section for debugging. */ FCS__OUTPUT_STATE(out_fh, "", &(state.s), &locs); #if 0 { FccEntryPointNode key; key.kv.key.key = item->key; fcs_lock_lock(&instance->fcc_entry_points_lock); FccEntryPointNode * val_proto = RB_FIND( FccEntryPointList, &(instance->fcc_entry_points), &(key) ); fcs_bool_t to_prune = FALSE; fcs_bool_t to_output = FALSE; if (val_proto) { val_proto->kv.val.is_reachable = TRUE; const int moves_count = instance->start_key_moves_count + item->moves_seq.count; if (was_start_key_reachable) { if (val_proto->kv.val.depth <= moves_count) { /* We can prune based on here. */ to_prune = TRUE; } else { /* We can set it to the more pessimstic move count * for future trimming. */ to_output = !(val_proto->kv.val.was_consumed); val_proto->kv.val.depth = moves_count; val_proto->kv.val.was_consumed = TRUE; } } else { if (! val_proto->kv.val.was_consumed) { to_output = TRUE; if (val_proto->kv.val.depth >= moves_count) { val_proto->kv.val.depth = moves_count; val_proto->kv.val.was_consumed = TRUE; } } } } fcs_lock_unlock(&instance->fcc_entry_points_lock); if (to_output) { const size_t needed_len = ( (sizeof(key.kv.key.key)+2) << 2 ) / 3 + 20; if (base64_encoding_buffer_max_len < needed_len) { base64_encoding_buffer = SREALLOC(base64_encoding_buffer, needed_len); base64_encoding_buffer_max_len = needed_len; } size_t unused_output_len; base64_encode( (unsigned char *)&(key.kv.key.key), sizeof(key.kv.key.key), base64_encoding_buffer, &unused_output_len ); fcs_lock_lock(&instance->output_lock); fprintf( instance->consumed_states_fh, "%s\n", base64_encoding_buffer ); fflush(instance->consumed_states_fh); fcs_lock_unlock(&instance->output_lock); } if (to_prune) { continue; } } #endif if (instance_solver_thread_calc_derived_states(local_variant, &state, token, &derived_list, &derived_list_recycle_bin, &derived_list_allocator, TRUE)) { fcs_lock_lock(&instance->global_lock); fcs_dbm__found_solution(&(instance->common), token, item); fcs_lock_unlock(&instance->global_lock); break; } /* Encode all the states. */ for (derived_iter = derived_list; derived_iter; derived_iter = derived_iter->next) { fcs_init_and_encode_state(delta_stater, local_variant, &(derived_iter->state), &(derived_iter->key)); } instance_check_multiple_keys(thread, instance, &(coll->cache_store), &(coll->queue_meta_alloc), &derived_list, 1 #ifdef FCS_DBM_CACHE_ONLY , item->moves_to_key #endif ); /* Now recycle the derived_list */ while (derived_list) { #define derived_list_next derived_iter derived_list_next = derived_list->next; derived_list->next = derived_list_recycle_bin; derived_list_recycle_bin = derived_list; derived_list = derived_list_next; #undef derived_list_next } /* End handle item. */ } /* End of main thread loop */ prev_item = item; } free(base64_encoding_buffer); fc_solve_compact_allocator_finish(&(derived_list_allocator)); TRACE("%s\n", "instance_run_solver_thread end"); return NULL; }