示例#1
0
        /// <summary>
        /// Fixes parent stat and node structures when a child is added
        /// </summary>
        /// <param name="parent">The parent.</param>
        /// <param name="child">The child.</param>
        /// <param name="txtime">The tx_time.</param>
        /// <param name="path">The path.</param>
        /// <param name="xid">The tx_id.</param>
        /// <param name="locklist">The locklist for this session.</param>
        void IUnsafeTreeAccess.UnsafeAddChild(IPersistedData parent, IPersistedData child, long txtime, string path, long xid, ILockListTransaction locklist)
        {
            if (parent == null)
            {
                throw new ArgumentNullException(nameof(parent));
            }

            if (child == null)
            {
                throw new ArgumentNullException(nameof(child));
            }

            if (locklist == null && this.IsPathLockedDown(path))
            {
                throw new InvalidAclException(path, "lockdown");
            }

            if (ForceWB || locklist == null)
            {
                this.secondarypreprocessor.AppendAddChild(parent.Id, child.Id, txtime, xid);
            }

            locklist?.ValidateLockList(parent, Perm.CREATE, child, Perm.WRITE);

            this.UpdateStat(parent, xid, txtime, ChangeKind.ChildrenAdded);
            parent.Node.AddChild(child.Node);

            parent.Node.ScheduleTriggerWatchers(ChangeKind.ChildrenAdded, path, locklist);
        }
示例#2
0
 private SetDataOperations(RequestSetData req, IPersistedData prevData, SetDataOperationCode operation, long number)
 {
     this.req       = req;
     this.prevData  = prevData;
     this.operation = operation;
     this.number    = number;
 }
示例#3
0
        /// <inheritdoc />
        public void AppendCreate(IPersistedDataFactory <Node> factory, IPersistedData data, long txtime)
        {
            if (factory == null)
            {
                throw new ArgumentNullException("factory");
            }

            if (data == null)
            {
                throw new ArgumentNullException("data");
            }

            if (this.changelist == null)
            {
                this.changelist = this.createChangeList();
            }

            data.AppendCreate(this.changelist);

            if (this.changelist != null)
            {
                this.changelist.SetTime(txtime);
            }

            if (this.isLockDown)
            {
                return;
            }

            this.RunOnAbort(() =>
            {
                factory.Delete(data);
            });
        }
示例#4
0
        /// <inheritdoc />
        public void AppendSetData(IPersistedData data, long txtime, byte[] prevData, IMutableStat prevStat)
        {
            if (data == null)
            {
                throw new ArgumentNullException("data");
            }

            if (prevStat == null)
            {
                throw new ArgumentNullException("prevStat");
            }

            if (this.changelist == null)
            {
                this.changelist = this.createChangeList();
            }

            data.AppendSetData(this.changelist);

            if (this.changelist != null)
            {
                this.changelist.SetTime(txtime);
            }

            if (this.isLockDown)
            {
                return;
            }

            this.RunOnAbort(() =>
            {
                data.Data = prevData;
                data.Stat = prevStat;
            });
        }
示例#5
0
        /// <summary>
        /// Fixes parent and child stats and node structures when a child is removed
        /// </summary>
        /// <param name="parent">The parent.</param>
        /// <param name="node">The node.</param>
        /// <param name="txtime">The tx_time.</param>
        /// <param name="path">The path.</param>
        /// <param name="xid">The tx_id.</param>
        /// <param name="locklist">The locklist for this session.</param>
        /// <param name="triggerWatcher">Whether to trigger watcher</param>
        void IUnsafeTreeAccess.UnsafeRemoveChild(IPersistedData parent, IPersistedData node, long txtime, string path, long xid, ILockListTransaction locklist, bool triggerWatcher)
        {
            if (parent == null)
            {
                throw new ArgumentNullException(nameof(parent));
            }

            if (node == null)
            {
                throw new ArgumentNullException(nameof(node));
            }

            if (locklist == null && this.IsPathLockedDown(path))
            {
                throw new InvalidAclException(path, "lockdown");
            }

            if (ForceWB || locklist == null)
            {
                this.secondarypreprocessor.AppendRemoveChild(parent.Id, node.Id, txtime, xid);
            }

            locklist?.ValidateLockList(parent, Perm.WRITE, node, Perm.WRITE);

            this.UpdateStat(parent, xid, txtime, ChangeKind.ChildrenRemoved);

            parent.Node.RemoveChild(node.Name);

            if (triggerWatcher)
            {
                parent.Node.ScheduleTriggerWatchers(ChangeKind.ChildrenRemoved, this.GetParentPath(path), locklist);
            }
        }
示例#6
0
        /// <summary>
        /// Records undeletion of a node.
        /// </summary>
        /// <param name="node">Node that is undeleted.</param>
        public void RecordNodeUndelete(IPersistedData node)
        {
            if (node == null)
            {
                throw new ArgumentNullException("node");
            }

            this.RecordStatsDelta(1, node.Stat.DataLength);
        }
示例#7
0
        /// <summary>
        /// Ensures the complete stat.
        /// </summary>
        /// <param name="persisted">The persisted.</param>
        /// <returns>IStat.</returns>
        internal static IMutableStat EnsureCompleteStat(IPersistedData persisted)
        {
            if (persisted.Stat is FirstStat)
            {
                return(new MutableStat(persisted.Stat));
            }

            return(persisted.Stat);
        }
            /// <summary>
            /// Appends the Create operation to the secondary preprocessor
            /// </summary>
            /// <param name="node">The node object.</param>
            /// <param name="txtime">The transaction time.</param>
            /// <param name="xid">The tranaction id.</param>
            internal void AppendCreate(IPersistedData node, long txtime, long xid)
            {
                if (this.wirebackup != null)
                {
                    this.wirebackup.AppendCreate(node, txtime, xid);
                }

                this.DoActionsOnApply(txtime, xid, this.runOnTxIdMultiples);
            }
示例#9
0
        /// <summary>
        /// Unsafe. Add ephemeral child.
        /// </summary>
        /// <param name="parent">The parent.</param>
        /// <param name="path">Path of the node to add</param>
        void IUnsafeTreeAccess.UnsafeAddEphemeralChild(IPersistedData parent, string path)
        {
            if (parent == null)
            {
                throw new ArgumentNullException(nameof(parent));
            }

            parent.Node.ScheduleTriggerWatchers(ChangeKind.ChildrenAdded, path, null);
        }
示例#10
0
        /// <summary>
        /// Fixes child stats and node structures when data (byte[]) change
        /// </summary>
        /// <param name="node">The node.</param>
        /// <param name="data">The data.</param>
        /// <param name="txtime">The tx_time.</param>
        /// <param name="path">The path.</param>
        /// <param name="xid">The tx_id.</param>
        /// <param name="locklist">The locklist for this session.</param>
        void IUnsafeTreeAccess.UnsafeSetData(IPersistedData node, byte[] data, long txtime, string path, long xid, ILockListTransaction locklist)
        {
            if (node == null)
            {
                throw new ArgumentNullException(nameof(node));
            }

            if (locklist == null && this.IsPathLockedDown(path))
            {
                throw new InvalidAclException(path, "lockdown");
            }

            if (ForceWB || locklist == null)
            {
                this.secondarypreprocessor.AppendSetData(node.Id, data, txtime, xid);
            }

            // It is possible for this setData to be a command for a replica.
            // if so, we will give it to the secondaryprocessor and let it decide what to do with it
            if (node.Name.Length >= 2 && node.Name[0] == '$' && node.Name[1] == '$' && this.secondarypreprocessor.ThisReplicaName != null)
            {
                this.secondarypreprocessor.TryRunCommand(node, data, txtime, xid);
            }

            locklist?.ValidateLockList(null, Perm.NONE, node, Perm.WRITE);
            int delta = -node.Stat.DataLength;

            if (data != null)
            {
                delta += data.Length;
            }

            this.UpdateStat(node, xid, txtime, ChangeKind.DataChanged, delta);
            node.Node.SetData(data);

            if (node.IsEphemeral)
            {
                this.EphemeralFactory.RecordDataDelta(delta);
            }
            else
            {
                if (locklist == null)
                {
                    this.Factory.RecordDataDelta(delta);
                }
                else
                {
                    locklist.RunOnCommit(() =>
                    {
                        this.Factory.RecordDataDelta(delta);
                    });
                }
            }

            node.Node.ScheduleTriggerWatchers(ChangeKind.DataChanged, path, locklist);
        }
示例#11
0
        /// <summary>
        /// Deletes the specified IPersistedData.
        /// </summary>
        /// <param name="node">The node.</param>
        public void Delete(IPersistedData node)
        {
            if (node == null)
            {
                throw new ArgumentNullException("node");
            }

            node.Delete();
            this.RecordStatsDelta(-1, -node.Stat.DataLength);
        }
示例#12
0
        /// <summary>
        ///  Associates the removal of this instance with the given <see cref="IChangeList"/>.
        /// </summary>
        /// <param name="changeList">The <see cref="IChangeList"/> to associate with</param>
        /// <param name="parent">The parent of this instance</param>
        /// <param name="isRecursive">If <c>true</c> the removal was recursive</param>
        public void AppendRemove(IChangeList changeList, IPersistedData parent, bool isRecursive = false)
        {
            PersistenceEventSource.Log.PersistedDataAppendRemove(this.Id, this.Name, isRecursive);

            // Log the change that this node, or the child, is removed.
            this.OnRemove(changeList);

            // Log the change on the parent, including Mzxid/Mtime in stat.
            ((PersistedData)parent).OnUpdate(changeList);
        }
示例#13
0
        /// <summary>
        /// Associates an update (where a child was added to this instnace) with the given <see cref="IChangeList"/>.
        /// </summary>
        /// <param name="changeList">The <see cref="IChangeList"/> to associate with</param>
        /// <param name="child">The child that was added</param>
        public void AppendAddChild(IChangeList changeList, IPersistedData child)
        {
            if (child == null)
            {
                throw new ArgumentNullException(nameof(child));
            }

            PersistenceEventSource.Log.PersistedDataAppendAddChild(this.Id, this.Name, child.Id, child.Name);
            this.OnUpdate(changeList);
        }
示例#14
0
        /// <inheritdoc />
        public void AppendRemove(IPersistedData parent, IPersistedData child, long txtime, IMutableStat prevChildStat, IMutableStat prevParentStat, Action recordUndeleteAction)
        {
            if (child == null)
            {
                throw new ArgumentNullException("child");
            }

            if (parent == null)
            {
                throw new ArgumentNullException("parent");
            }

            if (prevChildStat == null)
            {
                throw new ArgumentNullException("prevChildStat");
            }

            if (prevParentStat == null)
            {
                throw new ArgumentNullException("prevParentStat");
            }

            if (recordUndeleteAction == null)
            {
                throw new ArgumentNullException("recordUndeleteAction");
            }

            if (this.changelist == null)
            {
                this.changelist = this.createChangeList();
            }

            child.AppendRemove(this.changelist, parent);

            if (this.changelist != null)
            {
                this.changelist.SetTime(txtime);
            }

            if (this.isLockDown)
            {
                return;
            }

            this.RunOnAbort(() =>
            {
                this.ValidateLockList(parent, Perm.WRITE, null, Perm.NONE);

                recordUndeleteAction();

                parent.Node.AddChild(child.Node);
                child.Stat  = prevChildStat;
                parent.Stat = prevParentStat;
            });
        }
            /// <summary>
            /// Tries to run the command associated to the node, and encoded in the byte[]
            /// </summary>
            /// <param name="node">the node representing who will run the command</param>
            /// <param name="data">the data encoding the command. data must be a string encoded in UTF8, where the string is a RM command. RM commands are "$/[command]?arguments".</param>
            /// <param name="txtime">the time of the tx which contains the command</param>
            /// <param name="xid">the id of the tx which contains the command</param>
            /// <returns>trus if the command was executed. False otherwise</returns>
            internal bool TryRunCommand(IPersistedData node, byte[] data, long txtime, long xid)
            {
                if (node == null)
                {
                    throw new ArgumentNullException(nameof(node));
                }

                bool   didrun = false;
                string path   = Node.BuildPath(node);

                if (data == null || !this.CanRunInThisReplica(path))
                {
                    return(didrun);
                }

                this.DoActionsOnApply(
                    txtime,
                    xid,
                    (t, i) =>
                {
                    didrun = true;

                    string requestedCommand = null;
                    object content          = null;
                    string command          = null;

                    try
                    {
                        string datastr      = Encoding.UTF8.GetString(data);
                        byte[] argumentdata = null;
                        int p = datastr.IndexOf('?');

                        if (p == -1)
                        {
                            command = datastr;
                        }
                        else
                        {
                            command      = datastr.Substring(0, p);
                            argumentdata = Encoding.UTF8.GetBytes(datastr.Substring(p + 1));
                        }

                        Code res = this.backend.RmCommands.RunCommandPath(command, argumentdata, null, null, out requestedCommand, out content);
                        Trace.TraceInformation("command {0} was run at {1} with result {2}. content={3}", command, this.thisCommandPath, res, content);
                    }
                    catch (Exception e)
                    {
                        Trace.TraceInformation("command {0} was run at {1} (content={2}) with exception {3}. ", command, this.thisCommandPath, content, e);
                    }
                },
                    false);

                return(didrun);
            }
示例#16
0
        /// <summary>
        /// Appends a poison pill for the given path.
        /// </summary>
        /// <param name="data">The PD to poison.</param>
        /// <param name="spec">the Poison pill specification</param>
        /// <param name="txTime">The tx time.</param>
        public void AppendPoison(IPersistedData data, string spec, long txTime)
        {
            if (data == null)
            {
                throw new ArgumentNullException("data");
            }

            data.AppendPoison(spec, this.changelist);
            if (this.changelist != null)
            {
                this.changelist.SetTime(txTime);
            }
        }
示例#17
0
        /// <inheritdoc />
        void IUnsafeTreeAccess.DoNodeForAddChildren(IPersistedData parent, List <IPersistedData> children)
        {
            if (parent == null)
            {
                throw new ArgumentNullException(nameof(parent));
            }

            if (children == null)
            {
                throw new ArgumentNullException(nameof(children));
            }

            parent.Node.AddChildren(children);
        }
示例#18
0
            /// <summary>
            /// Adds the child.
            /// </summary>
            /// <param name="child">The child.</param>
            public void AddChild(IPersistedData child)
            {
                if (child == null)
                {
                    throw new ArgumentNullException("child");
                }

                if (child.Parent != null)
                {
                    child.Parent.RemoveChild(child);
                }

                child.Parent = this;
                this.childrenCount++;
            }
示例#19
0
        /// <summary>
        /// Adds a child to this node
        /// </summary>
        /// <param name="child">The child node to add</param>
        public void AddChild(IPersistedData child)
        {
            if (child == null)
            {
                throw new ArgumentNullException(nameof(child));
            }

            if (child.Parent != null)
            {
                PersistenceEventSource.Log.PersistedDataAddChild_RemovingChildFromExistingParent(child.Parent.Id, child.Parent.Name, child.Id, child.Name);
                child.Parent.RemoveChild(child);
            }

            child.Parent = this;
            PersistenceEventSource.Log.PersistedDataAddChild(this.Id, this.Name, child.Id, child.Name, this.GetChildrenCount());
        }
示例#20
0
        /// <summary>
        /// Fixes child stats and node structures when a node is created
        /// </summary>
        /// <param name="node">The node.</param>
        /// <param name="txtime">The tx_time.</param>
        /// <param name="path">The path.</param>
        /// <param name="xid">The tx_id.</param>
        /// <param name="locklist">The locklist for this session.</param>
        void IUnsafeTreeAccess.UnsafeCreate(IPersistedData node, long txtime, string path, long xid, ILockListTransaction locklist)
        {
            if (locklist == null && this.IsPathLockedDown(path))
            {
                throw new InvalidAclException(path, "lockdown");
            }

            if (ForceWB || locklist == null)
            {
                this.secondarypreprocessor.AppendCreate(node, txtime, xid);
            }

            this.UpdateStat(node, xid, txtime, ChangeKind.NodeCreated);
            this.DoNodeForCreate(node);

            node.Node.ScheduleTriggerWatchers(ChangeKind.NodeCreated, path, locklist);
        }
示例#21
0
            /// <summary>
            /// Creates an instance of <see cref="SetDataOperations"/> class
            /// </summary>
            /// <param name="prevData">Persisted data object</param>
            /// <param name="req">SetData request</param>
            /// <returns>instance of <see cref="SetDataOperations"/> class</returns>
            public static SetDataOperations TryCreate(IPersistedData prevData, RequestSetData req)
            {
                if (req == null)
                {
                    throw new ArgumentNullException(nameof(req));
                }

                SetDataOperationCode operation;
                long number;

                if (!SetDataOperationHelper.Instance.TryRead(req.Data, out operation, out number))
                {
                    return(null);
                }

                return(new SetDataOperations(req, prevData, operation, number));
            }
示例#22
0
        /// <summary>
        /// Fixes parent and child stats and node structures when a child is removed
        /// </summary>
        /// <param name="parent">The parent.</param>
        /// <param name="node">The node.</param>
        /// <param name="txtime">The tx_time.</param>
        /// <param name="path">The path.</param>
        /// <param name="xid">The tx_id.</param>
        /// <param name="locklist">The locklist for this session.</param>
        void IUnsafeTreeAccess.UnsafeRemove(IPersistedData parent, IPersistedData node, long txtime, string path, long xid, ILockListTransaction locklist)
        {
            if (parent == null)
            {
                throw new ArgumentNullException(nameof(parent));
            }

            if (node == null)
            {
                throw new ArgumentNullException(nameof(node));
            }

            ((IUnsafeTreeAccess)this).UnsafeRemoveChild(parent, node, txtime, path, xid, locklist, false);
            ((IUnsafeTreeAccess)this).UnsafeDeleteNode(parent, node, txtime, path, xid, locklist, false);

            node.Node.ScheduleTriggerWatchers(ChangeKind.NodeDeleted, path, locklist);
            parent.Node.ScheduleTriggerWatchers(ChangeKind.ChildrenRemoved, this.GetParentPath(path), locklist);
        }
示例#23
0
        /// <inheritdoc />
        public IMutableStat SnapStatIfNeeded(IPersistedData data)
        {
            if (this.isLockDown)
            {
                return(null);
            }

            if (data == null)
            {
                throw new ArgumentNullException("data");
            }

            if (data.Stat is FirstStat)
            {
                return(new FirstStat(data.Stat));
            }

            return(new MutableStat(data.Stat));
        }
示例#24
0
        /// <inheritdoc />
        public void AppendAddChild(IPersistedData parent, IPersistedData child, long txtime, IMutableStat prevStat)
        {
            if (parent == null)
            {
                throw new ArgumentNullException("parent");
            }

            if (child == null)
            {
                throw new ArgumentNullException("child");
            }

            if (prevStat == null)
            {
                throw new ArgumentNullException("prevStat");
            }

            if (this.changelist == null)
            {
                this.changelist = this.createChangeList();
            }

            parent.AppendAddChild(this.changelist, child);
            child.AppendSetParent(parent);

            if (this.changelist != null)
            {
                this.changelist.SetTime(txtime);
            }

            if (this.isLockDown)
            {
                return;
            }

            this.RunOnAbort(() =>
            {
                this.ValidateLockList(parent, Perm.WRITE, null, Perm.NONE);

                parent.Node.RemoveChild(child.Name);
                parent.Stat = prevStat;
            });
        }
示例#25
0
            /// <summary>
            /// Removes the child.
            /// </summary>
            /// <param name="child">The child.</param>
            public void RemoveChild(IPersistedData child)
            {
                if (child == null)
                {
                    throw new ArgumentNullException("child");
                }

                if (child.Parent == null)
                {
                    return;
                }

                if (child.Parent != this)
                {
                    RmAssert.Fail("cannot remove a node that is not a child.");
                }

                child.Parent = null;
                this.childrenCount--;
            }
示例#26
0
        /// <summary>
        /// Creates the node.
        /// </summary>
        /// <param name="pd">The persisted data object</param>
        /// <returns>Node object being created</returns>
        public static Node CreateNode(IPersistedData pd)
        {
            if (pd == null)
            {
                throw new ArgumentNullException(nameof(pd));
            }

            if (pd.Name.Length == 1 && pd.Name[0] == '/')
            {
                return(new RootNode(pd));
            }

            if (pd.GetChildrenCount() == 0)
            {
                return(new Node(pd));
            }
            else
            {
                return(new CompleteNode(pd));
            }
        }
示例#27
0
        /// <summary>
        /// Applies on the secondary the poison pill, if it is allowed in this configuration. Otherwise, does nothing.
        /// WARNING: THIS API IS NOT TO BE INVOKED EXCEPT FOR VALIDATING POISON PILLS!!!
        /// </summary>
        /// <param name="node">the PD this poison pill applies to</param>
        /// <param name="spec">the spec of the poison pill</param>
        /// <param name="txtime">the time for this tx</param>
        /// <param name="xid">the transdaction id</param>
        void IUnsafeTreeAccess.UnsafeSetPoisonPill(IPersistedData node, string spec, long txtime, long xid)
        {
            if (!ArePoisonPillAllowed)
            {
                return;
            }

            if (node == null)
            {
                throw new ArgumentNullException(nameof(node));
            }

            if (spec == null)
            {
                throw new ArgumentNullException(nameof(spec));
            }

            Trace.WriteLine(string.Format("Executing Poison Pill: {0} {1} {2} {3}", node.Name, spec, xid, txtime));

            // we will do things about the spec later. for now, just throw something when this is invoked.
            throw new InvalidOperationException(spec);
        }
示例#28
0
        /// <summary>
        /// Removes a child from this node.
        /// </summary>
        /// <param name="child">The child node to remove</param>
        public void RemoveChild(IPersistedData child)
        {
            if (child == null)
            {
                throw new ArgumentNullException(nameof(child));
            }

            if (child.Parent == null)
            {
                PersistenceEventSource.Log.PersistedDataRemoveChild_ParentIsNull(child.Id, child.Name);
                return;
            }

            if (child.Parent != this)
            {
                PersistenceEventSource.Log.PersistedDataRemoveChild_ParentIsNotThis(child.Id, child.Name, this.Id, this.Name, child.Parent.Id, child.Parent.Name);
                throw new InvalidOperationException("PersistedData.RemoveChild Failed-NotParent");
            }

            child.Parent = null;
            PersistenceEventSource.Log.PersistedDataRemoveChild(this.Id, this.Name, child.Id, child.Name, this.GetChildrenCount());
        }
示例#29
0
        /// <summary>
        /// Fixes parent and child stats and node structures when a child is removed
        /// </summary>
        /// <param name="parent">The parent.</param>
        /// <param name="node">The node.</param>
        /// <param name="txtime">The tx_time.</param>
        /// <param name="path">The path.</param>
        /// <param name="xid">The tx_id.</param>
        /// <param name="locklist">The locklist for this session.</param>
        /// <param name="triggerWatcher">Whether to trigger watcher</param>
        void IUnsafeTreeAccess.UnsafeDeleteNode(IPersistedData parent, IPersistedData node, long txtime, string path, long xid, ILockListTransaction locklist, bool triggerWatcher)
        {
            if (parent == null)
            {
                throw new ArgumentNullException(nameof(parent));
            }

            if (node == null)
            {
                throw new ArgumentNullException(nameof(node));
            }

            if (locklist == null && this.IsPathLockedDown(path))
            {
                throw new InvalidAclException(path, "lockdown");
            }

            if (ForceWB || locklist == null)
            {
                this.secondarypreprocessor.AppendDelete(parent.Id, node.Id, txtime, xid);
            }

            locklist?.ValidateLockList(parent, Perm.WRITE, node, Perm.WRITE);

            this.UpdateStat(node, xid, txtime, ChangeKind.NodeDeleted);
            if (node.IsEphemeral)
            {
                this.EphemeralFactory.Delete(node);
            }
            else
            {
                this.Factory.Delete(node);
            }

            if (triggerWatcher)
            {
                node.Node.ScheduleTriggerWatchers(ChangeKind.NodeDeleted, path, locklist);
            }
        }
示例#30
0
        /// <summary>
        /// Appends Create to file
        /// </summary>
        /// <param name="node">Node object</param>
        /// <param name="txtime">Transaction time</param>
        /// <param name="xid">Transaction ID</param>
        public void AppendCreate(IPersistedData node, long txtime, long xid)
        {
            if (this.toUpload == null)
            {
                return;
            }

            if (node == null)
            {
                throw new ArgumentNullException("node");
            }

            try
            {
                this.SetTx(xid);
                string line = string.Join("|", "CN", txtime, xid, node.Id, node.Name, ToString(node.Acl), ToString(node.Data));
                this.AppendLine(line);
            }
            catch (Exception e)
            {
                Console.WriteLine("Ignorable exception on Wirebackup AppendCreate: " + e.Message);
            }
        }