Esempio n. 1
0
        public YDoc RestoreDocument(YDoc originDoc, YDocOptions opts = null)
        {
            if (originDoc.Gc)
            {
                // We should try to restore a GC-ed document, because some of the restored items might have their content deleted.
                throw new Exception("originDoc must not be garbage collected");
            }

            using var encoder = new UpdateEncoderV2();
            originDoc.Transact(tr =>
            {
                int size = StateVector.Count(kvp => kvp.Value /* clock */ > 0);
                encoder.RestWriter.WriteVarUint((uint)size);

                // Splitting the structs before writing them to the encoder.
                foreach (var kvp in StateVector)
                {
                    int client = kvp.Key;
                    int clock  = kvp.Value;

                    if (clock == 0)
                    {
                        continue;
                    }

                    if (clock < originDoc.Store.GetState(client))
                    {
                        tr.Doc.Store.GetItemCleanStart(tr, new ID(client, clock));
                    }

                    var structs         = originDoc.Store.Clients[client];
                    var lastStructIndex = StructStore.FindIndexSS(structs, clock - 1);

                    // Write # encoded structs.
                    encoder.RestWriter.WriteVarUint((uint)(lastStructIndex + 1));
                    encoder.WriteClient(client);

                    // First clock written is 0.
                    encoder.RestWriter.WriteVarUint(0);

                    for (int i = 0; i <= lastStructIndex; i++)
                    {
                        structs[i].Write(encoder, 0);
                    }
                }

                DeleteSet.Write(encoder);
            });

            var newDoc = new YDoc(opts ?? originDoc.CloneOptionsWithNewGuid());

            newDoc.ApplyUpdateV2(encoder.ToArray(), transactionOrigin: "snapshot");
            return(newDoc);
        }
Esempio n. 2
0
        public void ReadAndApplyDeleteSet(IDSDecoder decoder, Transaction transaction)
        {
            var unappliedDs = new DeleteSet();
            var numClients  = decoder.Reader.ReadVarUint();

            for (int i = 0; i < numClients; i++)
            {
                decoder.ResetDsCurVal();

                var client          = (int)decoder.Reader.ReadVarUint();
                var numberOfDeletes = decoder.Reader.ReadVarUint();

                if (!Clients.TryGetValue(client, out var structs))
                {
                    structs = new List <AbstractStruct>();
                    // NOTE: Clients map is not updated.
                }

                var state = GetState(client);

                for (int deleteIndex = 0; deleteIndex < numberOfDeletes; deleteIndex++)
                {
                    var clock    = decoder.ReadDsClock();
                    var clockEnd = clock + decoder.ReadDsLength();
                    if (clock < state)
                    {
                        if (state < clockEnd)
                        {
                            unappliedDs.Add(client, state, clockEnd - state);
                        }

                        var index = StructStore.FindIndexSS(structs, clock);

                        // We can ignore the case of GC and Delete structs, because we are going to skip them.
                        var str = structs[index];

                        // Split the first item if necessary.
                        if (!str.Deleted && str.Id.Clock < clock)
                        {
                            var splitItem = (str as Item).SplitItem(transaction, clock - str.Id.Clock);
                            structs.Insert(index + 1, splitItem);

                            // Increase, we now want to use the next struct.
                            index++;
                        }

                        while (index < structs.Count)
                        {
                            str = structs[index++];
                            if (str.Id.Clock < clockEnd)
                            {
                                if (!str.Deleted)
                                {
                                    if (clockEnd < str.Id.Clock + str.Length)
                                    {
                                        var splitItem = (str as Item).SplitItem(transaction, clockEnd - str.Id.Clock);
                                        structs.Insert(index, splitItem);
                                    }

                                    str.Delete(transaction);
                                }
                            }
                            else
                            {
                                break;
                            }
                        }
                    }
                    else
                    {
                        unappliedDs.Add(client, clock, clockEnd - clock);
                    }
                }
            }

            if (unappliedDs.Clients.Count > 0)
            {
                // @TODO: No need for encoding+decoding ds anymore.
                using var unappliedDsEncoder = new DSEncoderV2();
                unappliedDs.Write(unappliedDsEncoder);
                _pendingDeleteReaders.Add(new DSDecoderV2(new MemoryStream(unappliedDsEncoder.ToArray())));
            }
        }