Example #1
0
        public void Integration_test()
        {
            var p0 = Replica.Empty(ReplicaId.New("p")).ApplyCmd(new Doc().DownField("key").Assign("A"));
            var q0 = Merge(Replica.Empty(ReplicaId.New("q")), p0);

            // Assert that p0 and q0 are converged
            Converged(p0, q0);

            var p1 = p0.ApplyCmd(new Doc().DownField("key").Assign("B"));
            var q1 = q0.ApplyCmd(new Doc().DownField("key").Assign("C"));

            // Assert that p1 and q1 are diverged
            Diverged(p1, q1);

            var p2 = Merge(p1, q1);
            var q2 = Merge(q1, p1);

            // Assert that p2 and q2 are converged again.
            Converged(p2, q2);
        }
Example #2
0
 private static Replica Merge(Replica a, Replica b)
 => a.ApplyRemoteOps(b.GeneratedOps);
Example #3
0
 private static void Converged(Replica a, Replica b, Replica c)
 {
     Converged(a, b);
     Converged(b, c);
 }
Example #4
0
        public Node ApplyOp(Operation op, Replica replica)
        {
            var view = op.Cursor.View();

            switch (view)
            {
            case Cursor.Leaf l:
            {
                switch (this)
                {
                case ListNode ln:
                {
                    IEnumerable <Operation> ConcurrentOpsSince(bigint count)
                    {
                        var allOps = replica.GeneratedOps.Append(replica.ReceivedOps);

                        throw new NotImplementedException();
                    }

                    var concurrentOps = ConcurrentOpsSince(op.Id.OpsCounter);

                    if (concurrentOps.Length() > 1 &&
                        concurrentOps.Select(x => x.Mutation).OfType <MoveVerticalM>().Length() >= 1)
                    {
                        //  Before applying an operation we save the order in orderArchive.
                        // It's a Map whose key is the lamport timestamp counter value.
                        // To improve performance and save disk space, we don't save the
                        // order before assign operations, since they don't change the order.
                        // Now there might be this situation: Alice did an assign and then a
                        // move op, while Bob did a move op. Now Bobs op comes in and
                        // Alice resets her order to the order with counter value like the
                        // incoming op. However, locally exists no such saved order, since
                        // she has done an assign op at that count. Therefore she resets
                        // to the next higher saved order.
                        // This fix is implemented by getting all orders whose counter is
                        // greater equals than the counter of the incoming op and then
                        // choosing the earliest order of those:
                        var newerOrders = ln.OrderArchive.Filter((k, v) => k >= op.Id.OpsCounter);

                        // restore the order
                        // TODO:
                        // val ctx1 =
                        //     if (newerOrders.nonEmpty) ln.copy(order = newerOrders.minBy {
                        //         case (c, _) => c
                        //     }._2)
                        //     else this
                        throw new NotImplementedException();

                        // Node ctx1 = this;

                        // return ctx1.ApplyMany(concurrentOps.OrderBy(x => x.Id));
                    }
                    else
                    {
                        // The op was done without me doing an op concurrently, so there is
                        // no need to restore anything. Just apply the op.
                        return(ApplyAtLeaf(op, replica));
                    }
                }

                default: return(ApplyAtLeaf(op, replica));
                }
                throw new InvalidOperationException("Invalid Cursor type");
            }

            case Cursor.Branch bn:
            {
                var child0 = GetChild(bn.Head);
                var child1 = child0.ApplyOp(op.Copy(cursor: bn.Tail), replica);
                var ctx1   = AddId(bn.Head, op.Id, op.Mutation);
                return(ctx1.AddNode(bn.Head, child1));
            }
            }

            return(this);
        }