/// <summary> /// Marks orphaned file records (the ones that do not have a referencing binary record anymore) as Deleted. /// </summary> public void CleanupFilesSetDeleteFlag() { var isLocalTransaction = false; if (!TransactionScope.IsActive) { TransactionScope.Begin(); isLocalTransaction = true; } try { using (var proc = new SqlProcedure { CommandText = CleanupFileSetIsdeletedScript, CommandType = CommandType.Text }) { proc.CommandType = CommandType.Text; proc.ExecuteNonQuery(); } if (isLocalTransaction && TransactionScope.IsActive) { TransactionScope.Commit(); } } catch (Exception ex) { if (isLocalTransaction && TransactionScope.IsActive) { TransactionScope.Rollback(); } throw new DataException("Error during setting deleted flag on files.", ex); } }
/// <summary> /// Finalizes a chunked save operation. /// </summary> /// <param name="versionId">Content version id.</param> /// <param name="propertyTypeId">Binary property type id.</param> /// <param name="fileId">File identifier.</param> /// <param name="fullSize">Full size (stream length) of the binary value.</param> /// <param name="source">Binary data containing metadata (e.g. content type).</param> public void CommitChunk(int versionId, int propertyTypeId, int fileId, long fullSize, BinaryDataValue source = null) { // start a new transaction here if needed var isLocalTransaction = !TransactionScope.IsActive; if (isLocalTransaction) { TransactionScope.Begin(); } try { // commit the process: set the final full size and checksum using (var cmd = new SqlProcedure { CommandText = CommitChunkScript, CommandType = CommandType.Text }) { cmd.Parameters.Add("@FileId", SqlDbType.Int).Value = fileId; cmd.Parameters.Add("@VersionId", SqlDbType.Int).Value = versionId; cmd.Parameters.Add("@PropertyTypeId", SqlDbType.Int).Value = propertyTypeId; cmd.Parameters.Add("@Size", SqlDbType.BigInt).Value = fullSize; cmd.Parameters.Add("@Checksum", SqlDbType.VarChar, 200).Value = DBNull.Value; cmd.Parameters.Add("@ContentType", SqlDbType.NVarChar, 50).Value = source != null ? source.ContentType : string.Empty; cmd.Parameters.Add("@FileNameWithoutExtension", SqlDbType.NVarChar, 450).Value = source != null ? source.FileName.FileNameWithoutExtension == null ? DBNull.Value : (object)source.FileName.FileNameWithoutExtension : DBNull.Value; cmd.Parameters.Add("@Extension", SqlDbType.NVarChar, 50).Value = source != null?ValidateExtension(source.FileName.Extension) : string.Empty; cmd.ExecuteNonQuery(); } } catch (Exception ex) { // rollback the transaction if it was opened locally if (isLocalTransaction && TransactionScope.IsActive) { TransactionScope.Rollback(); } throw new DataException("Error during committing binary chunk to file stream.", ex); } finally { // commit the transaction if it was opened locally if (isLocalTransaction && TransactionScope.IsActive) { TransactionScope.Commit(); } } }
private static Exception SaveNodeDataTransactional(Node node, NodeSaveSettings settings, IIndexPopulator populator, string originalPath, string newPath) { IndexDocumentData indexDocument = null; bool hasBinary = false; var data = node.Data; var isNewNode = data.Id == 0; NodeDataParticipant participant = null; var msg = "Saving Node#" + node.Id + ", " + node.ParentPath + "/" + node.Name; var isLocalTransaction = !TransactionScope.IsActive; using (var op = SnTrace.Database.StartOperation(msg)) { if (isLocalTransaction) { TransactionScope.Begin(); } try { // collect data for populator var populatorData = populator.BeginPopulateNode(node, settings, originalPath, newPath); data.CreateSnapshotData(); participant = new NodeDataParticipant { Data = data, Settings = settings, IsNewNode = isNewNode }; TransactionScope.Participate(participant); if (settings.NodeHead != null) { settings.LastMajorVersionIdBefore = settings.NodeHead.LastMajorVersionId; settings.LastMinorVersionIdBefore = settings.NodeHead.LastMinorVersionId; } int lastMajorVersionId, lastMinorVersionId; DataProvider.Current.SaveNodeData(data, settings, out lastMajorVersionId, out lastMinorVersionId); settings.LastMajorVersionIdAfter = lastMajorVersionId; settings.LastMinorVersionIdAfter = lastMinorVersionId; // here we re-create the node head to insert it into the cache and refresh the version info); if (lastMajorVersionId > 0 || lastMinorVersionId > 0) { var head = NodeHead.CreateFromNode(node, lastMinorVersionId, lastMajorVersionId); if (MustCache(node.NodeType)) { // participate cache items var idKey = CreateNodeHeadIdCacheKey(head.Id); var participant2 = new InsertCacheParticipant { CacheKey = idKey }; TransactionScope.Participate(participant2); var pathKey = CreateNodeHeadPathCacheKey(head.Path); var participant3 = new InsertCacheParticipant { CacheKey = pathKey }; TransactionScope.Participate(participant3); CacheNodeHead(head, idKey, pathKey); } node.RefreshVersionInfo(head); if (!settings.DeletableVersionIds.Contains(node.VersionId)) { // Elevation: we need to create the index document with full // control to avoid field access errors (indexing must be independent // from the current users permissions). using (new SystemAccount()) { indexDocument = SaveIndexDocument(node, true, isNewNode, out hasBinary); } } } if (isLocalTransaction) { TransactionScope.Commit(); } // populate index only if it is enabled on this content (e.g. preview images will be skipped) using (var op2 = SnTrace.Index.StartOperation("Indexing node")) { if (node.IsIndexingEnabled) { using (new SystemAccount()) populator.CommitPopulateNode(populatorData, indexDocument); } if (indexDocument != null && hasBinary) { using (new SystemAccount()) { indexDocument = SaveIndexDocument(node, indexDocument); populator.FinalizeTextExtracting(populatorData, indexDocument); } } op2.Successful = true; } } catch (NodeIsOutOfDateException) { RemoveFromCache(participant); throw; } catch (System.Data.Common.DbException dbe) { if (isLocalTransaction && IsDeadlockException(dbe)) { return(dbe); } throw SavingExceptionHelper(data, dbe); } catch (Exception e) { var ee = SavingExceptionHelper(data, e); if (ee == e) { throw; } else { throw ee; } } finally { if (isLocalTransaction && TransactionScope.IsActive) { TransactionScope.Rollback(); } } op.Successful = true; } return(null); }
private static bool SaveNodeDataTransactional(Node node, NodeSaveSettings settings, IIndexPopulator populator, string originalPath, string newPath) { IndexDocumentData indexDocument = null; bool hasBinary = false; var data = node.Data; var isNewNode = data.Id == 0; NodeDataParticipant participant = null; var isLocalTransaction = !TransactionScope.IsActive; if (isLocalTransaction) { TransactionScope.Begin(); } Logger.WriteVerbose("Transaction: " + TransactionScope.CurrentId + " SAVING " + node.Id + ", " + node.Path); try { //-- collect data for populator var populatorData = populator.BeginPopulateNode(node, settings, originalPath, newPath); data.CreateSnapshotData(); participant = new NodeDataParticipant { Data = data, Settings = settings, IsNewNode = isNewNode }; TransactionScope.Participate(participant); int lastMajorVersionId, lastMinorVersionId; DataProvider.Current.SaveNodeData(data, settings, out lastMajorVersionId, out lastMinorVersionId); //-- here we re-create the node head to insert it into the cache and refresh the version info); if (lastMajorVersionId > 0 || lastMinorVersionId > 0) { var head = NodeHead.CreateFromNode(node, lastMinorVersionId, lastMajorVersionId); if (MustCache(node.NodeType)) { //-- participate cache items var idKey = CreateNodeHeadIdCacheKey(head.Id); var participant2 = new InsertCacheParticipant { CacheKey = idKey }; TransactionScope.Participate(participant2); var pathKey = CreateNodeHeadPathCacheKey(head.Path); var participant3 = new InsertCacheParticipant { CacheKey = pathKey }; TransactionScope.Participate(participant3); CacheNodeHead(head, idKey, pathKey); } node.RefreshVersionInfo(head); if (!settings.DeletableVersionIds.Contains(node.VersionId)) { // Elevation: we need to create the index document with full // control to avoid field access errors (indexing must be independent // from the current users permissions). using (new SystemAccount()) { indexDocument = SaveIndexDocument(node, true, out hasBinary); } } } if (isLocalTransaction) { TransactionScope.Commit(); } //-- populate using (new SystemAccount()) populator.CommitPopulateNode(populatorData, indexDocument); if (indexDocument != null && hasBinary) { using (new SystemAccount()) { indexDocument = SaveIndexDocument(node, indexDocument); populator.FinalizeTextExtracting(populatorData, indexDocument); } } } catch (NodeIsOutOfDateException) { RemoveFromCache(participant); throw; } catch (System.Data.Common.DbException dbe) { Logger.WriteException(new Exception(string.Format("Error saving node. Id: {0}, Path: {1}", node.Id, node.Path), dbe)); if (isLocalTransaction && IsDeadlockException(dbe)) { return(false); } throw SavingExceptionHelper(data, dbe); } catch (Exception e) { Logger.WriteException(new Exception(string.Format("Error saving node. Id: {0}, Path: {1}", node.Id, node.Path), e)); var ee = SavingExceptionHelper(data, e); if (ee == e) { throw; } else { throw ee; } } finally { if (isLocalTransaction && TransactionScope.IsActive) { TransactionScope.Rollback(); } } return(true); }
/// <summary> /// Starts a chunked save operation on an existing content. It does not write any binary data /// to the storage, it only makes prerequisite operations - e.g. allocates a new slot in the storage. /// </summary> /// <param name="blobProvider">Blob storage provider.</param> /// <param name="versionId">Content version id.</param> /// <param name="propertyTypeId">Binary property type id.</param> /// <param name="fullSize">Full size (stream length) of the binary value.</param> /// <returns>A token containing all the information (db record ids) that identify a single entry in the blob storage.</returns> public string StartChunk(IBlobProvider blobProvider, int versionId, int propertyTypeId, long fullSize) { var isLocalTransaction = !TransactionScope.IsActive; if (isLocalTransaction) { TransactionScope.Begin(); } var ctx = new BlobStorageContext(blobProvider) { VersionId = versionId, PropertyTypeId = propertyTypeId, FileId = 0, Length = fullSize }; string blobProviderName = null; string blobProviderData = null; bool useSqlFileStream; if (IsBuiltInOrSqlFileStreamProvider(blobProvider)) { useSqlFileStream = SqlFileStreamBlobProvider.UseFileStream(blobProvider, fullSize); } else { useSqlFileStream = false; blobProvider.Allocate(ctx); blobProviderName = blobProvider.GetType().FullName; blobProviderData = BlobStorageContext.SerializeBlobProviderData(ctx.BlobProviderData); } try { using (var cmd = new SqlProcedure { CommandText = InsertStagingBinaryScript, CommandType = CommandType.Text }) { cmd.Parameters.Add("@VersionId", SqlDbType.Int).Value = versionId; cmd.Parameters.Add("@PropertyTypeId", SqlDbType.Int).Value = propertyTypeId; cmd.Parameters.Add("@Size", SqlDbType.BigInt).Value = fullSize; cmd.Parameters.Add("@UseSqlFileStream", SqlDbType.TinyInt).Value = useSqlFileStream ? 2 : 0; cmd.Parameters.Add("@BlobProvider", SqlDbType.NVarChar, 450).Value = blobProviderName != null ? (object)blobProviderName : DBNull.Value; cmd.Parameters.Add("@BlobProviderData", SqlDbType.NVarChar, int.MaxValue).Value = blobProviderData != null ? (object)blobProviderData : DBNull.Value; int binaryPropertyId; int fileId; using (var reader = cmd.ExecuteReader()) { if (reader.Read()) { binaryPropertyId = reader.GetSafeInt32(0); fileId = reader.GetSafeInt32(1); } else { throw new DataException("File row could not be inserted."); } } ctx.FileId = fileId; return(new ChunkToken { VersionId = versionId, PropertyTypeId = propertyTypeId, BinaryPropertyId = binaryPropertyId, FileId = fileId }.GetToken()); } } catch (Exception ex) { if (isLocalTransaction && TransactionScope.IsActive) { TransactionScope.Rollback(); } throw new DataException("Error during saving binary chunk to SQL Server.", ex); } finally { if (isLocalTransaction && TransactionScope.IsActive) { TransactionScope.Commit(); } } }
private static bool SaveNodeDataTransactional(Node node, NodeSaveSettings settings, out IndexDocumentData indexDocument) { indexDocument = null; var data = node.Data; var isNewNode = data.Id == 0; var isLocalTransaction = !TransactionScope.IsActive; if (isLocalTransaction) { TransactionScope.Begin(); } try { data.CreateSnapshotData(); var participant = new NodeDataParticipant { Data = data, Settings = settings, IsNewNode = isNewNode }; TransactionScope.Participate(participant); int lastMajorVersionId, lastMinorVersionId; DataProvider.Current.SaveNodeData(data, settings, out lastMajorVersionId, out lastMinorVersionId); //-- here we re-create the node head to insert it into the cache and refresh the version info if (lastMajorVersionId > 0 || lastMinorVersionId > 0) { var head = NodeHead.CreateFromNode(node, lastMinorVersionId, lastMajorVersionId); if (MustCache(node.NodeType)) { //-- participate cache items var idKey = CreateNodeHeadIdCacheKey(head.Id); var participant2 = new InsertCacheParticipant { CacheKey = idKey }; TransactionScope.Participate(participant2); var pathKey = CreateNodeHeadPathCacheKey(head.Path); var participant3 = new InsertCacheParticipant { CacheKey = pathKey }; TransactionScope.Participate(participant3); CacheNodeHead(head, idKey, pathKey); } node.RefreshVersionInfo(head); if (!settings.DeletableVersionIds.Contains(node.VersionId)) { indexDocument = SaveIndexDocument(node); } } if (isLocalTransaction) { TransactionScope.Commit(); } } catch (System.Data.Common.DbException dbe) { if (isLocalTransaction && IsDeadlockException(dbe)) { return(false); } throw SavingExceptionHelper(data, dbe); } catch (Exception e) { var ee = SavingExceptionHelper(data, e); if (ee == e) { throw; } else { throw ee; } } finally { if (isLocalTransaction && TransactionScope.IsActive) { TransactionScope.Rollback(); } } return(true); }