'Converts a batch of GrrMessages into a set of RDFValues at once.
Args:
metadata_value_pairs: a list or a generator of tuples (metadata, value),
where metadata is ExportedMetadata to be used for
conversion and value is a GrrMessage to be
converted.
token: Security token.
Returns:
Resulting RDFValues. Empty list is a valid result and means that
conversion wasn\'t possible.'

def BatchConvert(self, metadata_value_pairs, token=None):

    msg_dict = {}
    for (metadata, msg) in metadata_value_pairs:
        msg_dict.setdefault(msg.source, []).append((metadata, msg))
    metadata_objects = []
    metadata_to_fetch = []
    for client_urn in msg_dict.iterkeys():
        try:
            metadata_objects.append(self.cached_metadata[client_urn])
        except KeyError:
            metadata_to_fetch.append(client_urn)
    if metadata_to_fetch:
        client_fds = aff4.FACTORY.MultiOpen(metadata_to_fetch, mode='r', token=token)
        fetched_metadata = [GetMetadata(client_fd, token=token) for client_fd in client_fds]
        for metadata in fetched_metadata:
            self.cached_metadata[metadata.client_urn] = metadata
        metadata_objects.extend(fetched_metadata)
    data_by_type = {}
    for metadata in metadata_objects:
        try:
            for (original_metadata, message) in msg_dict[metadata.client_urn]:
                new_metadata = ExportedMetadata(metadata)
                new_metadata.source_urn = original_metadata.source_urn
                new_metadata.annotations = original_metadata.annotations
                new_metadata.original_timestamp = message.payload.age
                cls_name = message.payload.__class__.__name__
                if (cls_name not in data_by_type):
                    converters_classes = ExportConverter.GetConvertersByValue(message.payload)
                    data_by_type[cls_name] = {'converters': [cls(self.options) for cls in converters_classes], 'batch_data': [(new_metadata, message.payload)]}
                else:
                    data_by_type[cls_name]['batch_data'].append((new_metadata, message.payload))
        except KeyError:
            pass
    converted_batch = []
    for dataset in data_by_type.values():
        for converter in dataset['converters']:
            converted_batch.extend(converter.BatchConvert(dataset['batch_data'], token=token))
    return converted_batch
