static void compute_node_guid(td_engine *engine, td_node *node) { MD5_CTX context; MD5_Init(&context); md5_string(&context, node->action); md5_string(&context, node->annotation); md5_string(&context, node->salt); MD5_Final(node->guid.data, &context); if (td_debug_check(engine, TD_DEBUG_NODES)) { char guidstr[33]; td_digest_to_string(&node->guid, guidstr); printf("%s with guid %s\n", node->annotation, guidstr); } }
void td_setup_ancestor_data(td_engine *engine, td_node *node) { compute_node_guid(engine, node); ++engine->stats.ancestor_checks; if (engine->ancestors) { td_ancestor_data key; key.guid = node->guid; /* only key field is relevant */ node->ancestor_data = (td_ancestor_data *) bsearch(&key, engine->ancestors, engine->ancestor_count, sizeof(td_ancestor_data), td_compare_ancestors); if (node->ancestor_data) { int index = (int) (node->ancestor_data - engine->ancestors); td_node *other; if (NULL != (other = engine->ancestor_used[index])) td_croak("node error: nodes \"%s\" and \"%s\" share the same ancestor", node->annotation, other->annotation); engine->ancestor_used[index] = node; ++engine->stats.ancestor_nodes; } else { if (td_debug_check(engine, TD_DEBUG_ANCESTORS)) { char guidstr[33]; td_digest_to_string(&node->guid, guidstr); printf("no ancestor for %s with guid %s\n", node->annotation, guidstr); } } } else { /* We didn't load any ancestor data, just set the ancestor to NULL. * Everything will rebuild without ancestry. */ node->ancestor_data = NULL; } }
void td_save_ancestors(td_engine *engine, td_node *root) { FILE* f; int i, count, max_count; int output_cursor, write_count; td_ancestor_data *output; unsigned char *visited; time_t now = time(NULL); const int dbg = td_debug_check(engine, TD_DEBUG_ANCESTORS); if (NULL == (f = fopen(TD_ANCESTOR_FILE ".tmp", "wb"))) { fprintf(stderr, "warning: couldn't save ancestors\n"); return; } max_count = engine->node_count + engine->ancestor_count; output = (td_ancestor_data *) malloc(sizeof(td_ancestor_data) * max_count); visited = (unsigned char *) calloc(engine->ancestor_count, 1); output_cursor = 0; update_ancestors(engine, root, now, &output_cursor, output, visited); if (dbg) printf("refreshed %d ancestors\n", output_cursor); for (i = 0, count = engine->ancestor_count; i < count; ++i) { const td_ancestor_data *a = &engine->ancestors[i]; if (!visited[i] && !ancestor_timed_out(a, now)) output[output_cursor++] = *a; } if (dbg) printf("%d ancestors to save in total\n", output_cursor); qsort(output, output_cursor, sizeof(td_ancestor_data), td_compare_ancestors); if (dbg) { printf("full ancestor dump on save:\n"); for (i = 0; i < output_cursor; ++i) { char guid[33], sig[33]; td_digest_to_string(&output[i].guid, guid); td_digest_to_string(&output[i].input_signature, sig); printf("%s %s %ld %d\n", guid, sig, (long) output[i].access_time, output[i].job_result); } } write_count = (int) fwrite(output, sizeof(td_ancestor_data), output_cursor, f); fclose(f); free(visited); free(output); if (write_count != output_cursor) td_croak("couldn't write %d entries; only wrote %d", output_cursor, write_count); if (0 != td_move_file(TD_ANCESTOR_FILE ".tmp", TD_ANCESTOR_FILE)) td_croak("couldn't rename %s to %s", TD_ANCESTOR_FILE ".tmp", TD_ANCESTOR_FILE); }
static void update_input_signature(td_job_queue *queue, td_node *node) { static unsigned char zero_byte = 0; td_engine *engine = queue->engine; FILE* sign_debug_file = (FILE*) engine->sign_debug_file; int i, count; MD5_CTX context; td_mutex_unlock_or_die(&queue->mutex); MD5_Init(&context); if (sign_debug_file) fprintf(sign_debug_file, "begin signing \"%s\"\n", node->annotation); /* Add the command line */ if (node->action) { if (sign_debug_file) fprintf(sign_debug_file, "action = \"%s\"\n", node->action); MD5_Update(&context, (char*) node->action, (unsigned long) (strlen(node->action) + 1)); } else MD5_Update(&context, "", 1); for (i = 0, count = node->input_count; i < count; ++i) { td_file *input_file = node->inputs[i]; td_digest *digest = td_get_signature(engine, input_file); MD5_Update(&context, digest->data, sizeof(digest->data)); if (sign_debug_file) { char buffer[33]; td_digest_to_string(digest, buffer); fprintf(sign_debug_file, "input[%d] = %s (\"%s\")\n", i, buffer, input_file->path); } } /* add a separator between the inputs and implicit deps */ MD5_Update(&context, &zero_byte, 1); /* We technically invalidate the threading rules here and read the idep array. * * This is OK for the following reasons: * - The implicit dependencies for the node have already been scanned. * - They will never be scanned again (the DAG ensures this) * - The memory view of this array is already guaranteed consistent as we just released the lock. */ for (i = 0, count = node->job.idep_count; i < count; ++i) { td_file *dep = node->job.ideps[i]; td_digest *digest = td_get_signature(engine, dep); MD5_Update(&context, digest->data, sizeof(digest->data)); if (sign_debug_file) { char buffer[33]; td_digest_to_string(digest, buffer); fprintf(sign_debug_file, "implicit_input[%d] = %s (\"%s\")\n", i, buffer, dep->path); } } /* Grab the queue lock again before we publish the input signature */ td_mutex_lock_or_die(&queue->mutex); MD5_Final(node->job.input_signature.data, &context); if (sign_debug_file) { char buffer[33]; td_digest_to_string(&node->job.input_signature, buffer); fprintf(sign_debug_file, "resulting input signature = %s\n\n", buffer); } }