コード例 #1
0
ファイル: ancestors.c プロジェクト: jessewt/tundra
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);
	}
}
コード例 #2
0
ファイル: ancestors.c プロジェクト: jessewt/tundra
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;
	}
}
コード例 #3
0
ファイル: ancestors.c プロジェクト: jessewt/tundra
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);
}
コード例 #4
0
ファイル: build.c プロジェクト: greatwolf/tundra
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);
	}
}