static bool
aerospike_udf_put_is_done(aerospike* as, as_error * err, const as_policy_info* policy, char* filter)
{
	// Query all nodes for task completion status.
	bool done = true;
	as_nodes* nodes = as_nodes_reserve(as->cluster);
	
	for (uint32_t i = 0; i < nodes->size && done; i++) {
		as_node* node = nodes->array[i];
		struct sockaddr_in* sa_in = as_node_get_address(node);
		
		char* response = 0;
		as_status status = aerospike_info_socket_address(as, err, policy, sa_in, "udf-list", &response);
		
		if (status == AEROSPIKE_OK) {
			char* p = strstr(response, filter);
			
			if (! p) {
				done = false;
			}
			free(response);
		}
	}
	as_nodes_release(nodes);
	return done;
}
static bool
aerospike_index_create_is_done(aerospike* as, as_error * err, as_policy_info* policy, char* command)
{
	// Index is not done if any node reports percent completed < 100.
	// Errors are ignored and considered done.
	bool done = true;
	as_nodes* nodes = as_nodes_reserve(as->cluster);
	
	for (uint32_t i = 0; i < nodes->size && done; i++) {
		as_node* node = nodes->array[i];
		struct sockaddr_in* sa_in = as_node_get_address(node);
		
		char* response = 0;
		as_status status = aerospike_info_socket_address(as, err, policy, sa_in, command, &response);
		
		if (status == AEROSPIKE_OK) {
			char* find = "load_pct=";
			char* p = strstr(response, find);
			
			if (p) {
				p += strlen(find);
				char* q = strchr(p, ';');
				
				if (q) {
					*q = 0;
				}
				
				int pct = atoi(p);
				
				if (pct >= 0 && pct < 100) {
					done = false;
				}
			}
			cf_free(response);
		}
	}
	as_nodes_release(nodes);
	return done;
}