/// <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); }
private SetDataOperations(RequestSetData req, IPersistedData prevData, SetDataOperationCode operation, long number) { this.req = req; this.prevData = prevData; this.operation = operation; this.number = number; }
/// <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); }); }
/// <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; }); }
/// <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); } }
/// <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); }
/// <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); }
/// <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); }
/// <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); }
/// <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); }
/// <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); }
/// <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); }
/// <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); }
/// <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); } }
/// <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); }
/// <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++; }
/// <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()); }
/// <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); }
/// <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)); }
/// <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); }
/// <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)); }
/// <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; }); }
/// <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--; }
/// <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)); } }
/// <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); }
/// <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()); }
/// <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); } }
/// <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); } }