internal static void SaveNodeData(Node node, NodeSaveSettings settings, IIndexPopulator populator, string originalPath, string newPath) { var isNewNode = node.Id == 0; var isOwnerChanged = node.Data.IsPropertyChanged("OwnerId"); if (!isNewNode && isOwnerChanged) { node.Security.Assert(PermissionType.TakeOwnership); } var data = node.Data; var attempt = 0; using (var op = SnTrace.Database.StartOperation("SaveNodeData")) { while (true) { attempt++; var deadlockException = SaveNodeDataTransactional(node, settings, populator, originalPath, newPath); if (deadlockException == null) { break; } SnTrace.Database.Write("DEADLOCK detected. Attempt: {0}/{1}, NodeId:{2}, Version:{3}, Path:{4}", attempt, maxDeadlockIterations, node.Id, node.Version, node.Path); if (attempt >= maxDeadlockIterations) { throw new Exception(string.Format("Error saving node. Id: {0}, Path: {1}", node.Id, node.Path), deadlockException); } SnLog.WriteWarning("Deadlock detected in SaveNodeData", properties: new Dictionary <string, object> { { "Id: ", node.Id }, { "Path: ", node.Path }, { "Version: ", node.Version }, { "Attempt: ", attempt } }); System.Threading.Thread.Sleep(sleepIfDeadlock); } op.Successful = true; } try { if (isNewNode) { SecurityHandler.CreateSecurityEntity(node.Id, node.ParentId, node.OwnerId); } else if (isOwnerChanged) { SecurityHandler.ModifyEntityOwner(node.Id, node.OwnerId); } } catch (EntityNotFoundException e) { SnLog.WriteException(e, $"Error during creating or modifying security entity: {node.Id}. Original message: {e}", EventId.Security); } catch (SecurityStructureException) // suppressed { // no need to log this: somebody else already created or modified this security entity } if (isNewNode) { SnTrace.ContentOperation.Write("Node created. Id:{0}, Path:{1}", data.Id, data.Path); } else { SnTrace.ContentOperation.Write("Node updated. Id:{0}, Path:{1}", data.Id, data.Path); } }