Search code examples
c#database-deadlocksfiletable

Deadlock: Insert into a filetable statements appears to block one another


We are having trouble inserting into a filetable. This is our current constellation, I will try to explain it as detailed as possible:

Basically we have three tables:

  • T_Document (main metadata of a document)
  • T_Version (versioned metadata of a document)
  • T_Content (the binary content of a document, FileTable)

Our WCF service saves the documents and is being used by multiple persons. The service will open a transaction and will call the method SaveDocument which saves the documents:

//This is the point where the tranaction starts
using (IDBTransaction tran = db.GetTransaction())
{
    try
    {
        m_commandFassade.SaveDocument(document, m_loginName, db, options, lastVersion);
        tran.Commit();
        return document;
    }
    catch
    {
        tran.Rollback();
        throw;
    }
}

The SaveDocument method looks like this:

public void SaveDocument(E2TDocument document, string login, IDBConnection db, DocumentUploadOptions options, int lastVersion)
{
    document.GuardNotNull();
    options.GuardNotNull();

    if (lastVersion == -1)
    {
        //inserting new T_Document
        SaveDocument(document, db);
    }
    else
    {
        //updating the existing T_Document
        UpdateDocument(document, db); //document already exists, updating it
    }

    Guid contentID = Guid.NewGuid();
    //inserting the content
    SaveDocumentContent(document, contentID, db); 
    //inserting the new / initial version
    SaveDocumentVersion(document, contentID, db); 
}

Basically all the methods you see are either inserting or updating those three tables. The insert content query, that appears to make some trouble like this:

 INSERT INTO T_Content
       (stream_id
       ,file_stream
       ,name)
 VALUES
       (#ContentID
       ,#Content
       ,#Title) 

And the method (please take this as pseudo code):

    private void SaveDocumentContent(E2TDocument e2TDokument, Guid contentID, IDBConnection db)
    {
        using (m_log.CreateScope<MethodScope>(GlobalDefinitions.TracePriorityForData))
        {
            Command cmd = CommandFactory.CreateCommand("InsertContents");
            cmd.SetParameter("ContentID", contentID);
            cmd.SetParameter("Content", e2TDokument.Content);
            string title = string.Concat(e2TDokument.Titel.RemoveIllegalPathCharacters(), GlobalDefinitions.UNTERSTRICH,
                contentID).TrimToMaxLength(MaxLength_T_Contents_Col_Name, SuffixLength_T_Contents_Col_Name);
            cmd.SetParameter("Title", title);
            db.Execute(cmd);
        }
    }

I have no experience in deadlock-analysis, but the deadlock graphs show me that when inserting the content into the filetable, it appears to be deadlocked with another process also writing into the same table at the same time.

Deadlock (the other side shows the same statement, my application log confirms two concurrent tries to save documents)

The same deadlock appears 30 times a day. I already shrinked the transaction to a minimum, removing all unneccessary selects, but yet I had no luck to solve this issue.

What I'm most curious about is how its possible to deadlock on an insert into a filetable. Are there internal things that are being executed that I'm not aware of. I saw some strange statements in the profiler trace on that table, that we dont use anywhere in the code, e.g.:

set @pathlocator = convert(hierachyid, @path_locator__bin)

and things like:

if exists (
      select 1
             from [LGOL_Content01].[dbo].[T_Contents]
            where parent_path_locator = @path_locator
        )

If you need any more details, please let me know. Any tips how to proceed would be awesome.

Edit 1:\

Following you find the execution plan for the T_Content insert:

insert_exec_plan


Solution

  • So, after hours and hours and research and consulting with microsoft, the deadlock is actually a filetable / sql server related bug, which will be hotfixed by Microsoft.