public async Task <IReadOnlyCollection <ObjectVersionRecord> > GetObjectVersions(long id, string initialVersionId)
        {
            var objectDescriptors = new List <ObjectDescriptor>();

            async Task <(bool IsTruncated, int NextVersionIndex, string NextVersionIdMarker)> ListVersions(int nextVersionIndex, string nextVersionIdMarker)
            {
                await _distributedLockManager.EnsureLockNotExists(id);

                var response = await _s3Client.ListVersionsAsync(
                    new ListVersionsRequest
                {
                    BucketName      = _bucketName,
                    Prefix          = id.AsS3ObjectKey(Tokens.ObjectPostfix),
                    VersionIdMarker = nextVersionIdMarker
                });

                var nonDeletedVersions = response.Versions.FindAll(x => !x.IsDeleteMarker);

                nextVersionIndex += nonDeletedVersions.Count;

                var initialVersionIdReached = false;
                var versionInfos            = nonDeletedVersions
                                              .Aggregate(
                    new List <(string VersionId, DateTime LastModified)>(),
                    (list, next) =>
                {
                    initialVersionIdReached = initialVersionIdReached ||
                                              !string.IsNullOrEmpty(initialVersionId) &&
                                              initialVersionId.Equals(next.VersionId, StringComparison.OrdinalIgnoreCase);
                    if (!initialVersionIdReached)
                    {
                        list.Add((next.VersionId, next.LastModified));
                    }

                    return(list);
                });

                var descriptors = new ObjectDescriptor[versionInfos.Count];
                var partitioner = Partitioner.Create(versionInfos);
                var tasks       = partitioner.GetOrderablePartitions(_degreeOfParallelism)
                                  .Select(async partition =>
                {
                    while (partition.MoveNext())
                    {
                        var index       = partition.Current.Key;
                        var versionInfo = partition.Current.Value;

                        descriptors[index] = await GetObjectDescriptor(id, versionInfo.VersionId);
                    }
                });
                await Task.WhenAll(tasks);

                objectDescriptors.AddRange(descriptors);

                return(!initialVersionIdReached && response.IsTruncated, nextVersionIndex, response.NextVersionIdMarker);
            }

            var result = await ListVersions(0, null);

            if (objectDescriptors.Count == 0)
            {
                throw new ObjectNotFoundException($"Object '{id}' not found.");
            }

            while (result.IsTruncated)
            {
                result = await ListVersions(result.NextVersionIndex, result.NextVersionIdMarker);
            }

            var maxVersionIndex = result.NextVersionIndex;
            var records         = new ObjectVersionRecord[objectDescriptors.Count];

            for (var index = 0; index < objectDescriptors.Count; ++index)
            {
                var descriptor = objectDescriptors[index];
                records[index] = new ObjectVersionRecord(
                    descriptor.Id,
                    descriptor.VersionId,
                    --maxVersionIndex,
                    descriptor.LastModified,
                    new AuthorInfo(descriptor.Metadata.Author, descriptor.Metadata.AuthorLogin, descriptor.Metadata.AuthorLogin),
                    descriptor.Properties,
                    descriptor.Elements.Select(x => new ObjectVersionRecord.ElementRecord(x.TemplateCode, x.Value)).ToList(),
                    descriptor.Metadata.ModifiedElements);
            }

            return(records);
        }