예제 #1
0
/**
 * Parse a data placement policy.
 */
int _xml_parse_policy(xmlTextReaderPtr reader, struct ltfs_index *idx)
{
	declare_parser_vars("dataplacementpolicy");
	declare_tracking_arrays(1, 0);

	/* get rid of unused variable warning */
	(void) value;

	/* parse the contents of the policy tag */
	while (true) {
		get_next_tag();

		if (! strcmp(name, "indexpartitioncriteria")) {
			check_required_tag(0);
			assert_not_empty();
			if (_xml_parse_ip_criteria(reader, idx) < 0)
				return -1;

		} else
			ignore_unrecognized_tag();
	}

	check_required_tags();
	return 0;
}
예제 #2
0
/**
 * Parse a partition map from an XML file, storing it in the given label structure.
 */
int _xml_parse_partition_map(xmlTextReaderPtr reader, struct ltfs_label *label)
{
	declare_parser_vars("partitions");
	declare_tracking_arrays(2, 0);

	while (true) {
		get_next_tag();

		if (! strcmp(name, "index")) {
			check_required_tag(0);
			get_tag_text();
			if (_xml_parse_partition(value) < 0)
				return -1;
			label->partid_ip = value[0];
			check_tag_end("index");

		} else if (! strcmp(name, "data")) {
			check_required_tag(1);
			get_tag_text();
			if (_xml_parse_partition(value) < 0)
				return -1;
			label->partid_dp = value[0];
			check_tag_end("data");

		} else
			ignore_unrecognized_tag();
	}

	check_required_tags();
	return 0;
}
예제 #3
0
static int _xml_parse_symlink_target(xmlTextReaderPtr reader, int idx_version, struct dentry *d)
{
	declare_parser_vars_symlinknode("symlink");
	declare_tracking_arrays(1, 0);

	while (true) {
		get_next_tag();

		if (! strcmp(name, "target")) {
			get_tag_text();
			d->isslink = true;
			d->target = strdup(value);
		} else
			ignore_unrecognized_tag();
	}

	return 0;
}
예제 #4
0
/**
 * Parse an extent list from a file and populate provided dentry with the extents read during
 * the scanning.
 *
 * @param filename File name from where to read the extent list from.
 * @param d Dentry where the extents are to be appended to.
 * @return 0 on success or a negative value on error.
 */
static int xml_extentlist_from_file(const char *filename, struct dentry *d)
{
	declare_extent_parser_vars("extentinfo");
	xmlTextReaderPtr reader;
	xmlDocPtr doc;
	int ret = 0;

	CHECK_ARG_NULL(filename, -LTFS_NULL_ARG);
	CHECK_ARG_NULL(d, -LTFS_NULL_ARG);

	reader = xmlReaderForFile(filename, NULL, XML_PARSE_NOERROR | XML_PARSE_NOWARNING);
	if (! reader) {
		ltfsmsg(LTFS_ERR, "17011E", filename);
		return -1;
	}

	/* Workaround for old libxml2 version on OS X 10.5: the method used to preserve
	 * unknown tags modifies the behavior of xmlFreeTextReader so that an additional
	 * xmlDocFree call is required to free all memory. */
	doc = xmlTextReaderCurrentDoc(reader);

	while (true) { /* BEAM: loop doesn't iterate - Because get_next_tag() macro uses "break", at most once loop is needed here. */
		get_next_tag();
		if (! strcmp(name, "extentinfo")) {
			ret = _xml_parse_extents(reader, IDX_VERSION_SPARSE, d);
			if (ret < 0) {
				/* XML parser: failed to read extent list from file (%d) */
				ltfsmsg(LTFS_ERR, "17084E", ret);
			}
		}
		break;
	}

	if (doc)
		xmlFreeDoc(doc);
	xmlFreeTextReader(reader);

	return ret;
}
예제 #5
0
/**
 * Parse a partition location from a label.
 */
int _xml_parse_label_location(xmlTextReaderPtr reader, struct ltfs_label *label)
{
	declare_parser_vars("location");
	declare_tracking_arrays(1, 0);

	while (true) {
		get_next_tag();

		if (! strcmp(name, "partition")) {
			check_required_tag(0);
			get_tag_text();
			if (_xml_parse_partition(value) < 0)
				return -1;
			label->this_partition = value[0];
			check_tag_end("partition");

		} else
			ignore_unrecognized_tag();
	}

	check_required_tags();
	return 0;
}
예제 #6
0
/**
 * Parse a directory tree from the given XML source into the given index data structure.
 * @param reader the XML source
 * @param parent Directory where the new subdirectory should be created, or NULL to populate the
 *               root dentry.
 * @param idx LTFS index data
 * @param vol LTFS volume to which the index belongs. May be NULL.
 * @return 0 on success or a negative value on error
 */
int _xml_parse_dirtree(xmlTextReaderPtr reader, struct dentry *parent,
	struct ltfs_index *idx, struct ltfs_volume *vol, struct name_list *dirname)
{
	int ret;
	unsigned long long value_int;
	struct dentry *dir;
	declare_parser_vars("directory");
	declare_tracking_arrays(9, 1);

	if (! parent && idx->root) {
		dir = idx->root;
		dir->vol = vol;
	} else {
		dir = fs_allocate_dentry(parent, NULL, NULL, true, false, false, idx);
		if (! dir) {
			ltfsmsg(LTFS_ERR, "10001E", __FUNCTION__);
			return -LTFS_NO_MEMORY;
		}
		if (! parent) {
			idx->root = dir;
			dir->vol = vol;
			++dir->link_count;
		}
	}

	while (true) {
		get_next_tag();

		if (!strcmp(name, "name")) {
			check_required_tag(0);

			if (parent) {
				get_tag_text();
				if (xml_parse_filename(&dir->name, value) < 0)
					return -1;
				dirname->name = dir->name;
				dirname->d = dir;
				check_tag_end("name");
			} else {
				/* this is the root directory, so set the volume name */
				check_empty();
				if (empty > 0) {
					value = NULL;
				} else {
					if (xml_scan_text(reader, &value) < 0)
						return -1;
				}

				if (value && strlen(value) > 0) {
					if (xml_parse_filename(&idx->volume_name, value) < 0)
						return -1;
					/* if the value is the empty string, then xml_scan_text consumed the "name"
					 * element end */
					check_tag_end("name");
				} else
					idx->volume_name = NULL;
			}

		} else if (!strcmp(name, "readonly")) {
			check_required_tag(1);
			get_tag_text();
			if (xml_parse_bool(&dir->readonly, value) < 0)
				return -1;
			check_tag_end("readonly");

		} else if (!strcmp(name, "modifytime")) {
			check_required_tag(2);
			get_tag_text();
			ret = xml_parse_time(true, value, &dir->modify_time);
			if (ret < 0)
				return -1;
			else if (ret == LTFS_TIME_OUT_OF_RANGE)
				ltfsmsg(LTFS_WARN, "17220W", "updatetime", dir->name, dir->uid, value);

			check_tag_end("modifytime");

		} else if (!strcmp(name, "creationtime")) {
			check_required_tag(3);
			get_tag_text();
			ret = xml_parse_time(true, value, &dir->creation_time);
			if (ret < 0)
				return -1;
			else if (ret == LTFS_TIME_OUT_OF_RANGE)
				ltfsmsg(LTFS_WARN, "17220W", "creationtime", dir->name, dir->uid, value);

			check_tag_end("creationtime");

		} else if (!strcmp(name, "accesstime")) {
			check_required_tag(4);
			get_tag_text();
			ret = xml_parse_time(true, value, &dir->access_time);
			if (ret < 0)
				return -1;
			else if (ret == LTFS_TIME_OUT_OF_RANGE)
				ltfsmsg(LTFS_WARN, "17220W", "accesstime", dir->name, dir->uid, value);

			check_tag_end("accesstime");

		} else if (!strcmp(name, "changetime")) {
			check_required_tag(5);
			get_tag_text();
			ret = xml_parse_time(true, value, &dir->change_time);
			if (ret < 0)
				return -1;
			else if (ret == LTFS_TIME_OUT_OF_RANGE)
				ltfsmsg(LTFS_WARN, "17220W", "changetime", dir->name, dir->uid, value);

			check_tag_end("changetime");

		} else if (! strcmp(name, "contents")) {
			check_required_tag(6);
			check_empty();
			if (empty == 0 && (ret = _xml_parse_dir_contents(reader, dir, idx)) < 0) {
				if (ret == -LTFS_NO_MEMORY)
					return ret;
				else
					return -1;
			}

		} else if (!strcmp(name, "extendedattributes")) {
			check_optional_tag(0);
			check_empty();
			if (empty == 0 && _xml_parse_xattrs(reader, dir) < 0)
					return -1;

		} else if (idx->version >= IDX_VERSION_UID && ! strcmp(name, UID_TAGNAME)) {
			check_required_tag(7);
			get_tag_text();
			if (xml_parse_ull(&value_int, value) < 0)
				return -1;
			dir->uid = value_int;
			if (dir->uid > idx->uid_number)
				idx->uid_number = dir->uid;
			if (parent) {
				dirname->uid  = dir->uid;
			}
			check_tag_end(UID_TAGNAME);
		} else if (! strcmp(name, UID_TAGNAME)) {
			ignore_unrecognized_tag();

		} else if (idx->version >= IDX_VERSION_BACKUPTIME && ! strcmp(name, BACKUPTIME_TAGNAME)) {
			check_required_tag(8);
			get_tag_text();
			ret = xml_parse_time(true, value, &dir->backup_time);
			if (ret < 0)
				return -1;
			else if (ret == LTFS_TIME_OUT_OF_RANGE)
				ltfsmsg(LTFS_WARN, "17220W", "backuptime", dir->name, dir->uid, value);

			check_tag_end(BACKUPTIME_TAGNAME);
		} else if (! strcmp(name, BACKUPTIME_TAGNAME)) {
			ignore_unrecognized_tag();

		} else
			preserve_unrecognized_tag(dir);
	}

	/* For old index versions, allocate a UID */
	if (idx->version < IDX_VERSION_UID) {
		check_required_tag(7);
		if (parent) {
			dir->uid = fs_allocate_uid(idx);
			if (dir->uid > idx->uid_number)
				idx->uid_number = dir->uid;
			dirname->uid  = dir->uid;
		}
		/* root directory already got assigned UID 1 by fs_allocate_dentry */
	}

	/* For old index versions, set backup time equal to creation time */
	if (idx->version < IDX_VERSION_BACKUPTIME) {
		check_required_tag(8);
		dir->backup_time = dir->creation_time;
	}

	check_required_tags();

	/* Validate UID: root directory must have uid==1, other dentries must have nonzero UID */
	/* TODO: would be nice to verify that there are no UID conflicts */
	if (parent && dir->uid == 1) {
		ltfsmsg(LTFS_ERR, "17101E");
		return -1;
	} else if (! parent && dir->uid != 1) {
		ltfsmsg(LTFS_ERR, "17100E");
		return -1;
	} else if (dir->uid == 0) {
		ltfsmsg(LTFS_ERR, "17106E");
		return -1;
	}

	return 0;
}
예제 #7
0
/**
 * Parse index partition criteria.
 */
int _xml_parse_ip_criteria(xmlTextReaderPtr reader, struct ltfs_index *idx)
{
	int ret;
	unsigned long long value_int;
	char *glob_norm;
	int num_patterns = 0;
	declare_parser_vars("indexpartitioncriteria");
	declare_tracking_arrays(1, 0);

	/* clear the glob pattern list first */
	index_criteria_free(&idx->original_criteria);
	index_criteria_free(&idx->index_criteria);

	/* We have a policy. */
	idx->original_criteria.have_criteria = true;

	while (true) {
		get_next_tag();

		if (! strcmp(name, "size")) {
			check_required_tag(0);
			get_tag_text();
			if (xml_parse_ull(&value_int, value) < 0) {
				ltfsmsg(LTFS_ERR, "17024E", value);
				return -1;
			}
			idx->original_criteria.max_filesize_criteria = value_int;
			check_tag_end("size");

		} else if (! strcmp(name, "name")) {
			get_tag_text();

			if (pathname_validate_file(value) < 0) {
				ltfsmsg(LTFS_ERR, "17098E", value);
				return -1;
			}

			++num_patterns;
			/* quite inefficient, but the number of patterns should be small. */
			idx->original_criteria.glob_patterns = realloc(idx->original_criteria.glob_patterns,
				(num_patterns + 1) * sizeof(char *));
			if (! idx->original_criteria.glob_patterns) {
				ltfsmsg(LTFS_ERR, "10001E", __FUNCTION__);
				return -1;
			}
			idx->original_criteria.glob_patterns[num_patterns] = NULL;

			ret = pathname_normalize(value, &glob_norm);
			if (ret < 0) {
				ltfsmsg(LTFS_ERR, "17025E", ret);
				return ret;
			}
			idx->original_criteria.glob_patterns[num_patterns - 1] = glob_norm;

			check_tag_end("name");

		} else
			ignore_unrecognized_tag();
	}

	/* Make an active copy of these index criteria. The caller can override idx->index_criteria
	 * later without affecting the criteria stored in future indexes (idx->original_criteria). */
	if (index_criteria_dup_rules(&idx->index_criteria, &idx->original_criteria) < 0) {
		/* Could not duplicate index criteria rules */
		ltfsmsg(LTFS_ERR, "11301E");
		return -1;
	}

	check_required_tags();
	return 0;
}
예제 #8
0
/**
 * Parse an index file from the given source and populate the priv->root virtual dentry tree.
 * with the nodes found during the scanning.
 * @param reader Source of XML data
 * @param idx LTFS index
 * @param vol LTFS volume to which the index belongs. May be NULL.
 * @return 0 on success or a negative value on error.
 */
int _xml_parse_schema(xmlTextReaderPtr reader, struct ltfs_index *idx, struct ltfs_volume *vol)
{
	int ret;
	unsigned long long value_int;
	declare_parser_vars("ltfsindex");
	declare_tracking_arrays(8, 3);

	/* start the parser: find top-level "index" tag, check version and encoding */
	ret = _xml_parser_init(reader, parent_tag, &idx->version,
						   LTFS_INDEX_VERSION_MIN, LTFS_INDEX_VERSION_MAX);
	if (ret < 0)
		return ret;

	if (idx->version < LTFS_INDEX_VERSION)
		ltfsmsg(LTFS_WARN, "17095W",
				LTFS_INDEX_VERSION_STR,
				LTFS_FORMAT_MAJOR(idx->version),
				LTFS_FORMAT_MINOR(idx->version),
				LTFS_FORMAT_REVISION(idx->version));
	else if (idx->version / 100 > LTFS_INDEX_VERSION / 100)
		ltfsmsg(LTFS_WARN, "17096W",
				LTFS_INDEX_VERSION_STR,
				LTFS_FORMAT_MAJOR(idx->version),
				LTFS_FORMAT_MINOR(idx->version),
				LTFS_FORMAT_REVISION(idx->version));
	else if (idx->version > LTFS_INDEX_VERSION)
		ltfsmsg(LTFS_WARN, "17234W",
				LTFS_INDEX_VERSION_STR,
				LTFS_FORMAT_MAJOR(idx->version),
				LTFS_FORMAT_MINOR(idx->version),
				LTFS_FORMAT_REVISION(idx->version));

	if (idx->commit_message) {
		free(idx->commit_message);
		idx->commit_message = NULL;
	}

	/* parse index file contents */
	while (true) {
		get_next_tag();

		if (! strcmp(name, "creator")) {
			check_required_tag(0);
			get_tag_text();
			if (idx->creator)
				free(idx->creator);
			idx->creator = strdup(value);
			if (! idx->creator) {
				ltfsmsg(LTFS_ERR, "10001E", name);
				return -1;
			}
			check_tag_end("creator");

		} else if (! strcmp(name, "volumeuuid")) {
			check_required_tag(1);
			get_tag_text();
			if (xml_parse_uuid(idx->vol_uuid, value) < 0)
				return -1;
			check_tag_end("volumeuuid");

		} else if (! strcmp(name, "generationnumber")) {
			check_required_tag(2);
			get_tag_text();
			if (xml_parse_ull(&value_int, value) < 0) {
				ltfsmsg(LTFS_ERR, "17023E", value);
				return -1;
			}
			idx->generation = value_int;
			check_tag_end("generationnumber");

		} else if (! strcmp(name, "updatetime")) {
			check_required_tag(3);
			get_tag_text();
			ret = xml_parse_time(true, value, &idx->mod_time);
			if (ret < 0)
				return -1;
			else if (ret == LTFS_TIME_OUT_OF_RANGE)
				ltfsmsg(LTFS_WARN, "17219W", "updatetime", value);

			check_tag_end("updatetime");

		} else if (! strcmp(name, "location")) {
			check_required_tag(4);
			assert_not_empty();
			if (_xml_scan_tapepos(reader, "location", &idx->selfptr) < 0)
				return -1;

		} else if (! strcmp(name, "allowpolicyupdate")) {
			check_required_tag(5);
			get_tag_text();
			if (xml_parse_bool(&idx->criteria_allow_update, value) < 0)
				return -1;
			check_tag_end("allowpolicyupdate");

		} else if (! strcmp(name, "directory")) {
			check_required_tag(6);
			assert_not_empty();
			if ((ret = _xml_parse_dirtree(reader, NULL, idx, vol, NULL)) < 0) {
				if (ret == -LTFS_NO_MEMORY)
					return -LTFS_NO_MEMORY;
				else
					return -1;
			}

		} else if (! strcmp(name, "previousgenerationlocation")) {
			check_optional_tag(0);
			assert_not_empty();
			if (_xml_scan_tapepos(reader, "previousgenerationlocation", &idx->backptr) < 0)
				return -1;

		} else if (! strcmp(name, "dataplacementpolicy")) {
			check_optional_tag(1);
			assert_not_empty();
			if (_xml_parse_policy(reader, idx) < 0)
				return -1;

		} else if (! strcmp(name, "comment")) {
			check_optional_tag(2);
			get_tag_text();
			if (strlen(value) > INDEX_MAX_COMMENT_LEN) {
				ltfsmsg(LTFS_ERR, "17094E");
				return -1;
			}
			idx->commit_message = strdup(value);
			if (! idx->commit_message) {
				ltfsmsg(LTFS_ERR, "10001E", "_xml_parse_schema: index comment");
				return -1;
			}
			check_tag_end("comment");

		} else if (idx->version >= IDX_VERSION_UID && ! strcmp(name, NEXTUID_TAGNAME)) {
			check_required_tag(7);
			get_tag_text();
			if (xml_parse_ull(&value_int, value) < 0)
				return -1;
			if (value_int > idx->uid_number)
				idx->uid_number = value_int;
			check_tag_end(NEXTUID_TAGNAME);
		} else if (! strcmp(name, NEXTUID_TAGNAME)) {
			ignore_unrecognized_tag();

		} else
			preserve_unrecognized_tag(idx);
	}

	/* For older index versions, assume we handle UIDs correctly.
	 * The idx->uid_number field is automatically initialized to 1, so it will be set correctly
	 * once all files and directories are parsed. */
	if (idx->version < IDX_VERSION_UID)
		check_required_tag(7);

	check_required_tags();

	if ( idx->symerr_count != 0 ) {
		return -LTFS_SYMLINK_CONFLICT;
	}


	return 0;
}
예제 #9
0
/**
 * Parse an XML label, populating the given label data structure.
 */
int _xml_parse_label(xmlTextReaderPtr reader, struct ltfs_label *label)
{
	int ret;
	unsigned long long value_int;
	declare_parser_vars("ltfslabel");
	declare_tracking_arrays(7, 0);

	/* start the parser: find top-level "label" tag, check version and encoding */
	if (_xml_parser_init(reader, parent_tag, &label->version,
		LTFS_LABEL_VERSION_MIN, LTFS_LABEL_VERSION_MAX) < 0)
		return -1;

	/* parse label contents */
	while (true) {
		get_next_tag();

		if (! strcmp(name, "creator")) {
			check_required_tag(0);
			get_tag_text();
			if (label->creator) {
				free(label->creator); 
				label->creator = NULL;
			}
			label->creator = strdup(value);
			if (! label->creator) {
				ltfsmsg(LTFS_ERR, "10001E", name);
				return -1;
			}
			check_tag_end("creator");

		} else if (! strcmp(name, "formattime")) {
			check_required_tag(1);
			get_tag_text();
			ret = xml_parse_time(true, value, &label->format_time);
			if (ret < 0)
				return -1;
			else if (ret == LTFS_TIME_OUT_OF_RANGE)
				ltfsmsg(LTFS_WARN, "17218W", "formattime", value);
			check_tag_end("formattime");

		} else if (! strcmp(name, "volumeuuid")) {
			check_required_tag(2);
			get_tag_text();
			if (xml_parse_uuid(label->vol_uuid, value) < 0)
				return -1;
			check_tag_end("volumeuuid");

		} else if (! strcmp(name, "location")) {
			check_required_tag(3);
			assert_not_empty();
			if (_xml_parse_label_location(reader, label) < 0)
				return -1;

		} else if (! strcmp(name, "partitions")) {
			check_required_tag(4);
			assert_not_empty();
			if (_xml_parse_partition_map(reader, label) < 0)
				return -1;

		} else if (! strcmp(name, "blocksize")) {
			check_required_tag(5);
			get_tag_text();
			if (xml_parse_ull(&value_int, value) < 0 || value_int == 0) {
				ltfsmsg(LTFS_ERR, "17022E", value);
				return -1;
			}
			label->blocksize = value_int;
			check_tag_end("blocksize");

		} else if (! strcmp(name, "compression")) {
			check_required_tag(6);
			get_tag_text();
			if (xml_parse_bool(&label->enable_compression, value) < 0)
				return -1;
			check_tag_end("compression");

		} else
			ignore_unrecognized_tag();
	}

	check_required_tags();
	return 0;
}
예제 #10
0
int _xml_parse_dir_contents(xmlTextReaderPtr reader, struct dentry *dir, struct ltfs_index *idx)
{
	int ret = 0;
	struct name_list *list = NULL, *entry_name = NULL;
	CHECK_ARG_NULL(dir, -LTFS_NULL_ARG);
	declare_parser_vars("contents");
	declare_tracking_arrays(0, 0);

	/* get rid of unused variable warning */
	(void) value;
	errno = 0;

	while (true) {
		get_next_tag();

		if (! strcmp(name, "file")) {
			assert_not_empty();
			entry_name = (struct name_list *)malloc(sizeof(struct name_list));
			if (!entry_name) {
				ltfsmsg(LTFS_ERR, "10001E", "_xml_parse_dir_contents: file");
				return -LTFS_NO_MEMORY;
			}
			if ((ret = _xml_parse_file(reader, idx, dir, entry_name)) < 0) {
				free(entry_name);
				if (ret == -LTFS_NO_MEMORY)
					return -LTFS_NO_MEMORY;
				else
					return -1;
			}

		} else if (! strcmp(name, "directory")) {
			assert_not_empty();
			entry_name = (struct name_list *)malloc(sizeof(struct name_list));
			if (!entry_name) {
				ltfsmsg(LTFS_ERR, "10001E", "_xml_parse_dir_contents: dir");
				return -LTFS_NO_MEMORY;
			}
			if ((ret =_xml_parse_dirtree(reader, dir, idx, dir->vol, entry_name)) < 0) {
				free(entry_name);
				if (ret == -LTFS_NO_MEMORY)
					return -LTFS_NO_MEMORY;
				else
					return -1;
			}

		} else {
			ignore_unrecognized_tag();
			entry_name = NULL;
		}
		if (!strcmp(name, "file") || (!strcmp(name, "directory") && !(!dir && idx->root))) {
			/* Make temporal hash table whose key is dentry name */
			HASH_ADD_KEYPTR(hh, list, entry_name->name, strlen(entry_name->name), entry_name);
			if (errno == ENOMEM) {
				struct name_list *list_ptr, *list_tmp;

				HASH_ITER(hh, list, list_ptr, list_tmp) {
					HASH_DEL(list, list_ptr);
					free(list_ptr);
				}

				ltfsmsg(LTFS_ERR, "10001E", "_xml_parse_dir_contents: add key");
				/* HP fix for double free when a tape with a large index file is mounted
				 * on a host with low physical memory
				 */
				/*free(entry_name);*/

				return -LTFS_NO_MEMORY;
			}
		} else {
예제 #11
0
    void connection_handler::handle_messages()
    {
        detail::handling_messages hm(handling_messages_);       // reset on exit

        bool bootstrapping = hpx::is_starting();
        bool has_work = true;
        std::size_t k = 0;

        hpx::util::high_resolution_timer t;
        std::list<std::pair<int, MPI_Request> > close_requests;

        // We let the message handling loop spin for another 2 seconds to avoid the
        // costs involved with posting it to asio
        while(bootstrapping || has_work || (!has_work && t.elapsed() < 2.0))
        {
            if(stopped_) break;

            // break the loop if someone requested to pause the parcelport
            if(!enable_parcel_handling_) break;

            // handle all send requests
            {
                hpx::lcos::local::spinlock::scoped_lock l(senders_mtx_);
                for(
                    senders_type::iterator it = senders_.begin();
                    !stopped_ && enable_parcel_handling_ && it != senders_.end();
                    /**/)
                {
                    if((*it)->done())
                    {
                        it = senders_.erase(it);
                    }
                    else
                    {
                        ++it;
                    }
                }
                has_work = !senders_.empty();
            }

            // Send the pending close requests
            {
                hpx::lcos::local::spinlock::scoped_lock l(close_mtx_);
                typedef std::pair<int, int> pair_type;

                BOOST_FOREACH(pair_type p, pending_close_requests_)
                {
                    header close_request = header::close(p.first, p.second);
                    close_requests.push_back(std::make_pair(p.first, MPI_Request()));
                    MPI_Isend(
                        close_request.data(),         // Data pointer
                        close_request.data_size_,     // Size
                        close_request.type(),         // MPI Datatype
                        close_request.rank(),         // Destination
                        0,                            // Tag
                        communicator_,                // Communicator
                        &close_requests.back().second
                    );
                }
                pending_close_requests_.clear();
            }

            // add new receive requests
            std::pair<bool, header> next(acceptor_.next_header());
            if(next.first)
            {
                boost::shared_ptr<receiver> rcv;
                header h = next.second;

                receivers_tag_map_type & tag_map = receivers_map_[h.rank()];

                receivers_tag_map_type::iterator jt = tag_map.find(h.tag());

                if(jt != tag_map.end())
                {
                    rcv = jt->second;
                }
                else
                {
                    rcv = boost::make_shared<receiver>(
                        communicator_
                      , get_next_tag()
                      , h.tag()
                      , h.rank()
                      , *this);
                    tag_map.insert(std::make_pair(h.tag(), rcv));
                }

                if(h.close_request())
                {
                    rcv->close();
                }
                else
                {
                    h.assert_valid();
                    if (static_cast<std::size_t>(h.size()) > this->get_max_message_size())
                    {
                        // report this problem ...
                        HPX_THROW_EXCEPTION(boost::asio::error::operation_not_supported,
                            "mpi::connection_handler::handle_messages",
                            "The size of this message exceeds the maximum inbound data size");
                        return;
                    }
                    if(rcv->async_read(h))
                    {
#ifdef HPX_DEBUG
                        receivers_type::iterator it = std::find(receivers_.begin(), receivers_.end(), rcv);
                        HPX_ASSERT(it == receivers_.end());

#endif
                        receivers_.push_back(rcv);
                    }
                }
            }

            // handle all receive requests
            for(receivers_type::iterator it = receivers_.begin();
                it != receivers_.end(); /**/)
            {
                boost::shared_ptr<receiver> rcv = *it;
                if(rcv->done())
                {
                    HPX_ASSERT(rcv->sender_tag() != -1);
                    if(rcv->closing())
                    {
                        receivers_tag_map_type & tag_map = receivers_map_[rcv->rank()];

                        receivers_tag_map_type::iterator jt = tag_map.find(rcv->sender_tag());
                        HPX_ASSERT(jt != tag_map.end());
                        tag_map.erase(jt);
                        {
                            hpx::lcos::local::spinlock::scoped_lock l(tag_mtx_);
                            free_tags_.push_back(rcv->tag());
                        }
                    }
                    it = receivers_.erase(it);
                }
                else
                {
                    ++it;
                }
            }
            if(!has_work) has_work = !receivers_.empty();

            // handle completed close requests
            for(
                std::list<std::pair<int, MPI_Request> >::iterator it = close_requests.begin();
                !stopped_ && enable_parcel_handling_ && it != close_requests.end();
            )
            {
                int completed = 0;
                MPI_Status status;
                int ret = 0;
                ret = MPI_Test(&it->second, &completed, &status);
                HPX_ASSERT(ret == MPI_SUCCESS);
                if(completed && status.MPI_ERROR != MPI_ERR_PENDING)
                {
                    hpx::lcos::local::spinlock::scoped_lock l(tag_mtx_);
                    free_tags_.push_back(it->first);
                    it = close_requests.erase(it);
                }
                else
                {
                    ++it;
                }
            }
            if(!has_work)
                has_work = !close_requests.empty();

            if (bootstrapping)
                bootstrapping = hpx::is_starting();

            if(has_work)
            {
                t.restart();
                k = 0;
            }
            else
            {
                if(enable_parcel_handling_)
                {
                    hpx::lcos::local::spinlock::yield(k);
                    ++k;
                }
            }
        }
예제 #12
0
    void connection_handler::handle_messages()
    {
        detail::handling_messages hm(handling_messages_);       // reset on exit

        bool bootstrapping = hpx::is_starting();
        bool has_work = true;
        std::size_t k = 0;

        hpx::util::high_resolution_timer t;
        std::list<std::pair<int, MPI_Request> > close_requests;

        // We let the message handling loop spin for another 2 seconds to avoid the
        // costs involved with posting it to asio
        while(bootstrapping || (!stopped_ && has_work) || (!has_work && t.elapsed() < 2.0))
        {
            // break the loop if someone requested to pause the parcelport
            if(!enable_parcel_handling_) break;

            // handle all send requests
            {
                hpx::lcos::local::spinlock::scoped_lock l(senders_mtx_);
                for(
                    senders_type::iterator it = senders_.begin();
                    !stopped_ && enable_parcel_handling_ && it != senders_.end();
                    /**/)
                {
                    if((*it)->done())
                    {
                        it = senders_.erase(it);
                    }
                    else
                    {
                        ++it;
                    }
                }
                has_work = !senders_.empty();
            }

            // Send the pending close requests
            {
                hpx::lcos::local::spinlock::scoped_lock l(close_mtx_);
                typedef std::pair<int, int> pair_type;

                BOOST_FOREACH(pair_type p, pending_close_requests_)
                {
                    header close_request = header::close(p.first, p.second);
                    close_requests.push_back(std::make_pair(p.first, MPI_Request()));
                    MPI_Isend(
                        close_request.data(),         // Data pointer
                        close_request.data_size_,     // Size
                        close_request.type(),         // MPI Datatype
                        close_request.rank(),         // Destination
                        0,                            // Tag
                        communicator_,                // Communicator
                        &close_requests.back().second
                    );
                }
                pending_close_requests_.clear();
            }

            // add new receive requests
            std::pair<bool, header> next(acceptor_.next_header());
            if(next.first)
            {
                boost::shared_ptr<receiver> rcv;
                receivers_rank_map_type::iterator jt = receivers_map_.find(next.second.rank());
                if(jt != receivers_map_.end())
                {
                    receivers_tag_map_type::iterator kt = jt->second.find(next.second.tag());
                    if(kt != jt->second.end())
                    {
                        if(next.second.close_request())
                        {
                            hpx::lcos::local::spinlock::scoped_lock l(tag_mtx_);
                            free_tags_.push_back(kt->second->tag());
                            jt->second.erase(kt);
                            if(jt->second.empty())
                            {
                                receivers_map_.erase(jt);
                            }
                        }
                        else
                        {
                            rcv = kt->second;
                        }
                    }
                }
                if(!next.second.close_request())
                {
                    next.second.assert_valid();
                    if(!rcv)
                    {
                        rcv = boost::make_shared<receiver>(communicator_, get_next_tag());
                    }
                    rcv->async_read(next.second, *this);
                    receivers_.push_back(rcv);
                }
            }

            // handle all receive requests
            for(
                receivers_type::iterator it = receivers_.begin();
                !stopped_ && enable_parcel_handling_ && it != receivers_.end();
                /**/)
            {
                if((*it)->done(*this))
                {
                    HPX_ASSERT(
                        !receivers_map_[(*it)->rank()][(*it)->sender_tag()]
                     || receivers_map_[(*it)->rank()][(*it)->sender_tag()].get() == it->get()
                    );
                    receivers_map_[(*it)->rank()][(*it)->sender_tag()] = *it;
                    it = receivers_.erase(it);
                }
                else
                {
                    ++it;
                }
            }

            if(!has_work) has_work = !receivers_.empty();

            // handle completed close requests
            for(
                std::list<std::pair<int, MPI_Request> >::iterator it = close_requests.begin();
                !stopped_ && enable_parcel_handling_ && it != close_requests.end();
            )
            {
                int completed = 0;
                MPI_Status status;
                int ret = 0;
                ret = MPI_Test(&it->second, &completed, &status);
                HPX_ASSERT(ret == MPI_SUCCESS);
                if(completed && status.MPI_ERROR != MPI_ERR_PENDING)
                {
                    hpx::lcos::local::spinlock::scoped_lock l(tag_mtx_);
                    free_tags_.push_back(it->first);
                    it = close_requests.erase(it);
                }
                else
                {
                    ++it;
                }
            }
            if(!has_work)
                has_work = !close_requests.empty();

            if (bootstrapping)
                bootstrapping = hpx::is_starting();

            if(has_work)
            {
                t.restart();
                k = 0;
            }
            else
            {
                if(enable_parcel_handling_)
                {
                    hpx::lcos::local::spinlock::yield(k);
                    ++k;
                }
            }
        }