コード例 #1
0
        public override async ValueTask <CommitRef?> ReadCommitRefAsync(string branch, string name, CancellationToken cancellationToken)
        {
            if (string.IsNullOrWhiteSpace(branch))
            {
                throw new ArgumentNullException(nameof(branch));
            }
            if (string.IsNullOrWhiteSpace(name))
            {
                throw new ArgumentNullException(nameof(name));
            }

            var filename = DeriveCommitRefFileName(branch, name);
            var path     = Path.Combine(_refsContainer, filename);

            var bytes = await ReadFileAsync(path, cancellationToken).ConfigureAwait(false);

            // NotFound
            if (bytes == null || bytes.Length == 0)
            {
                return(null);
            }

            // CommitIds are not compressed
            var commitId = Serializer.DeserializeCommitId(bytes);

            var commitRef = new CommitRef(name, commitId);

            return(commitRef);
        }
コード例 #2
0
        public override async ValueTask <IReadOnlyList <CommitRef> > GetBranchesAsync(string name, CancellationToken cancellationToken)
        {
            var filename = DeriveCommitRefFileName(name, null);
            var path     = Path.Combine(_refsContainer, filename);
            var files    = Directory.GetFiles(path, "*" + CommitExtension, SearchOption.TopDirectoryOnly);

            var results = new CommitRef[files.Length];

            for (var i = 0; i < results.Length; i++)
            {
                var bytes = await ReadFileAsync(files[i], cancellationToken).ConfigureAwait(false);

                var branch = Path.ChangeExtension(Path.GetFileName(files[i]), null);

                var commitId = Serializer.DeserializeCommitId(bytes);
                results[i] = new CommitRef(branch, commitId);
            }
            return(results);
        }
コード例 #3
0
ファイル: CommitRefTests.cs プロジェクト: hello-web/Chasm
        public static void CommitRef_equality()
        {
            var commitRef1 = new CommitRef("abc", new CommitId(Sha1.Hash("abc")));
            var commitRef2 = new CommitRef("abc", new CommitId(Sha1.Hash("abc")));
            var commitRef3 = new CommitRef("def", new CommitId(Sha1.Hash("def")));

            Assert.True(commitRef1 == commitRef2);
            Assert.False(commitRef1 != commitRef2);
            Assert.True(commitRef1.Equals((object)commitRef2));

            Assert.Equal(commitRef1, commitRef2);
            Assert.Equal(commitRef1.GetHashCode(), commitRef2.GetHashCode());
            Assert.Equal(commitRef1.ToString(), commitRef2.ToString());

            Assert.NotEqual(CommitRef.Empty, commitRef1);
            Assert.NotEqual(CommitRef.Empty.GetHashCode(), commitRef1.GetHashCode());

            Assert.NotEqual(commitRef3, commitRef1);
            Assert.NotEqual(commitRef3.GetHashCode(), commitRef1.GetHashCode());
            Assert.NotEqual(commitRef3.ToString(), commitRef1.ToString());
        }
コード例 #4
0
        public override async ValueTask <CommitRef?> ReadCommitRefAsync(string branch, string name, CancellationToken cancellationToken)
        {
            if (string.IsNullOrWhiteSpace(branch))
            {
                throw new ArgumentNullException(nameof(branch));
            }
            if (string.IsNullOrWhiteSpace(name))
            {
                throw new ArgumentNullException(nameof(name));
            }

            var(found, commitId, _, _) = await ReadCommitRefImplAsync(branch, name, cancellationToken).ConfigureAwait(false);

            // NotFound
            if (!found)
            {
                return(null);
            }

            // Found
            var commitRef = new CommitRef(name, commitId);

            return(commitRef);
        }
コード例 #5
0
 public override Task WriteCommitRefAsync(CommitId?previousCommitId, string branch, CommitRef commitRef, CancellationToken cancellationToken)
 {
     throw new NotImplementedException();
 }
コード例 #6
0
ファイル: ChasmRepository.cs プロジェクト: hello-web/Chasm
 public abstract Task WriteCommitRefAsync(CommitId?previousCommitId, string name, CommitRef commitRef, CancellationToken cancellationToken);
コード例 #7
0
        private static async Task TestRepository(IChasmRepository repository)
        {
            var g = Guid.NewGuid();

            var data = g.ToByteArray();
            var sha  = Sha1.Hash(data);

            // Unknown SHA
            var usha  = Sha1.Hash(Guid.NewGuid().ToByteArray());
            var usha2 = Sha1.Hash(Guid.NewGuid().ToByteArray());

            // Blob
            await repository.WriteObjectAsync(sha, new ArraySegment <byte>(data), false, default);

            var rdata = (await repository.ReadObjectAsync(sha, default));

            Assert.True(rdata.HasValue);
            Assert.Equal(16, rdata.Value.Length);
            Assert.Equal(g, rdata.Value.Span.NonPortableCast <byte, Guid>()[0]);

            var urdata = await repository.ReadObjectAsync(usha, default);

            Assert.False(urdata.HasValue);

            // Tree
            var tree = new TreeNodeMap(
                new TreeNode("firstItem", NodeKind.Blob, sha),
                new TreeNode("secondItem", NodeKind.Blob, sha)
                );
            var treeId = await repository.WriteTreeAsync(tree, default);

            var rtree = await repository.ReadTreeAsync(treeId, default);

            Assert.True(rtree.HasValue);
            Assert.Equal(tree, rtree.Value);

            var urtree = await repository.ReadTreeAsync(new TreeId(usha), default);

            Assert.False(urtree.HasValue);

            // Commit
            var commit = new Commit(
                new CommitId?(),
                treeId,
                new Audit("User1", DateTimeOffset.UtcNow.AddDays(-1)),
                new Audit("User2", DateTimeOffset.UtcNow),
                "Initial commit"
                );
            var commitId = await repository.WriteCommitAsync(commit, default);

            var rcommit = await repository.ReadCommitAsync(commitId, default);

            Assert.True(rcommit.HasValue);
            Assert.Equal(commit, rcommit);

            var urcommit = await repository.ReadCommitAsync(new CommitId(usha), default);

            Assert.False(urcommit.HasValue);

            // CommitRef
            var commitRefName = Guid.NewGuid().ToString("N");
            var commitRef     = new CommitRef("production", commitId);
            await repository.WriteCommitRefAsync(null, commitRefName, commitRef, default);

            var rcommitRef = await repository.ReadCommitRefAsync(commitRefName, commitRef.Branch, default);

            Assert.True(rcommit.HasValue);
            Assert.Equal(commitRef, rcommitRef);

            var urcommitRef = await repository.ReadCommitRefAsync(commitRefName + "_", commitRef.Branch, default);

            Assert.False(urcommit.HasValue);

            await Assert.ThrowsAsync <ChasmConcurrencyException>(() =>
                                                                 repository.WriteCommitRefAsync(null, commitRefName, new CommitRef("production", new CommitId(usha)), default));

            await Assert.ThrowsAsync <ChasmConcurrencyException>(() =>
                                                                 repository.WriteCommitRefAsync(new CommitId(usha2), commitRefName, new CommitRef("production", new CommitId(usha)), default));

            await repository.WriteCommitRefAsync(null, commitRefName, new CommitRef("dev", commitId), default);

            await repository.WriteCommitRefAsync(null, commitRefName, new CommitRef("staging", new CommitId(usha)), default);

            await repository.WriteCommitRefAsync(null, commitRefName + "_1", new CommitRef("production", new CommitId(usha)), default);

            var names = await repository.GetNamesAsync(default);
コード例 #8
0
        public override async Task WriteCommitRefAsync(CommitId?previousCommitId, string branch, CommitRef commitRef, CancellationToken cancellationToken)
        {
            if (string.IsNullOrWhiteSpace(branch))
            {
                throw new ArgumentNullException(nameof(branch));
            }
            if (commitRef == CommitRef.Empty)
            {
                throw new ArgumentNullException(nameof(commitRef));
            }

            // Load existing commit ref in order to use its etag
            var(found, existingCommitId, ifMatchCondition, blobRef) = await ReadCommitRefImplAsync(branch, commitRef.Name, cancellationToken).ConfigureAwait(false);

            // Optimistic concurrency check
            if (found)
            {
                // We found a previous commit but the caller didn't say to expect one
                if (!previousCommitId.HasValue)
                {
                    throw BuildConcurrencyException(branch, commitRef.Name, null); // TODO: May need a different error
                }
                // Semantics follow Interlocked.Exchange (compare then exchange)
                if (existingCommitId != previousCommitId.Value)
                {
                    throw BuildConcurrencyException(branch, commitRef.Name, null);
                }

                // Idempotent
                if (existingCommitId == commitRef.CommitId) // We already know that the name matches
                {
                    return;
                }
            }
            // The caller expected a previous commit, but we didn't find one
            else if (previousCommitId.HasValue)
            {
                throw BuildConcurrencyException(branch, commitRef.Name, null); // TODO: May need a different error
            }

            try
            {
                // Required to create blob before appending to it
                await blobRef.CreateOrReplaceAsync(ifMatchCondition, default, default, cancellationToken).ConfigureAwait(false); // Note etag access condition
コード例 #9
0
        public override async Task WriteCommitRefAsync(CommitId?previousCommitId, string name, CommitRef commitRef, CancellationToken cancellationToken)
        {
            if (string.IsNullOrWhiteSpace(name))
            {
                throw new ArgumentNullException(nameof(name));
            }
            if (commitRef == CommitRef.Empty)
            {
                throw new ArgumentNullException(nameof(commitRef));
            }

            // We only write to last repo
            var last = Chain[Chain.Length - 1];
            await last.WriteCommitRefAsync(previousCommitId, name, commitRef, cancellationToken).ConfigureAwait(false);
        }
コード例 #10
0
        public override async Task WriteCommitRefAsync(CommitId?previousCommitId, string branch, CommitRef commitRef, CancellationToken cancellationToken)
        {
            if (string.IsNullOrWhiteSpace(branch))
            {
                throw new ArgumentNullException(nameof(branch));
            }
            if (commitRef == CommitRef.Empty)
            {
                throw new ArgumentNullException(nameof(commitRef));
            }

            // TODO: Optimistic concurrency

            var filename = DeriveCommitRefFileName(branch, commitRef.Name);
            var path     = Path.Combine(_refsContainer, filename);

            // CommitIds are not compressed
            using (var session = Serializer.Serialize(commitRef.CommitId))
            {
                await WriteFileAsync(path, session.Result, cancellationToken).ConfigureAwait(false);
            }
        }
コード例 #11
0
        public override async Task WriteCommitRefAsync(CommitId?previousCommitId, string branch, CommitRef commitRef, CancellationToken cancellationToken)
        {
            if (string.IsNullOrWhiteSpace(branch))
            {
                throw new ArgumentNullException(nameof(branch));
            }
            if (commitRef == CommitRef.Empty)
            {
                throw new ArgumentNullException(nameof(commitRef));
            }

            // Load existing commit ref in order to use its etag
            var(found, existingCommitId, etag) = await ReadCommitRefImplAsync(branch, commitRef.Name, Serializer, cancellationToken).ConfigureAwait(false);

            // Optimistic concurrency check
            if (found)
            {
                // We found a previous commit but the caller didn't say to expect one
                if (!previousCommitId.HasValue)
                {
                    throw BuildConcurrencyException(branch, commitRef.Name, null); // TODO: May need a different error
                }
                // Semantics follow Interlocked.Exchange (compare then exchange)
                if (previousCommitId.HasValue && existingCommitId != previousCommitId.Value)
                {
                    throw BuildConcurrencyException(branch, commitRef.Name, null);
                }

                // Idempotent
                if (existingCommitId == commitRef.CommitId)
                {
                    return;
                }
            }
            // The caller expected a previous commit, but we didn't find one
            else if (previousCommitId.HasValue)
            {
                throw BuildConcurrencyException(branch, commitRef.Name, null); // TODO: May need a different error
            }

            try
            {
                var refsTable = _refsTable.Value;

                // CommitIds are not compressed
                using (var session = Serializer.Serialize(commitRef.CommitId))
                {
                    var op = DataEntity.BuildWriteOperation(branch, commitRef.Name, session.Result, etag); // Note etag access condition

                    await refsTable.ExecuteAsync(op).ConfigureAwait(false);
                }
            }
            catch (StorageException se) when(se.RequestInformation.HttpStatusCode == (int)HttpStatusCode.Conflict)
            {
                throw BuildConcurrencyException(branch, commitRef.Name, se);
            }
        }