Hi,

We are upgrading to 5.0.10 from 4.6, I have the following null reference exception. We don't have the source code yet so I can't give you more information than the following callstack.

  1. Is there a way to have access to the PDB of 5.0.10 to help debugging ?
  2. I don't have the exception if the SessionOptions include NotTransactionalReads (here the sessionOptions I am using : SessionOptions.ValidateEntities | SessionOptions.AutoActivation | SessionOptions.AutoSaveChanges

    Test method xxxxxxxxxxxxxxxx threw exception: System.NullReferenceException: Object reference not set to an instance of an object. Result StackTrace:
    at Xtensive.Tuples.TupleExtensions.GetFieldStateMap(Tuple target, TupleFieldState requestedState) at Xtensive.Orm.Providers.Persister.CreateUpdateTask(PersistAction action, Boolean validateVersion) at Xtensive.Orm.Providers.Persister.CreatePersistTask(PersistAction action, Boolean validateVersion) at Xtensive.Orm.Providers.Persister.Persist(EntityChangeRegistry registry, CommandProcessor processor) at Xtensive.Orm.Providers.SqlSessionHandler.Persist(EntityChangeRegistry registry, Boolean allowPartialExecution) at Xtensive.Orm.Session.Persist(PersistReason reason) at Xtensive.Orm.Session.CommitTransaction(Transaction transaction) at Xtensive.Orm.Transaction.Commit() at Xtensive.Orm.TransactionScope.Dispose()

Regards, Benoit

asked Aug 24 '16 at 07:08

Benoit%20Nesme's gravatar image

Benoit Nesme
43192024

edited Aug 24 '16 at 07:12

I have not been able to reproduce it with a sample yet. When I can say when debugging using DotPeek is that DifferentialTuple.Difference is null which leads to the null reference in GetFieldStateMap.

(Aug 24 '16 at 07:13) Benoit Nesme Benoit%20Nesme's gravatar image

2 Answers:

Hello Benoit Nesme

I will try to reproduce same behavior using your explanation. I will update my answer during investigation.

Customers can buy access to Sources and PDB files on FastSpring page.

answered Aug 29 '16 at 11:48

Alexey%20Kulakov's gravatar image

Alexey Kulakov
73215

Hi Alexey, do you have any update on this old questions, it is appearing again in production, and working around it is not possible anymore ?

(Jan 08 at 03:50) rle rle's gravatar image

Speaking of the case below it seems to be OK now.

In development branch we also fixed another case of incorrect rollback - when SQL transaction is killed by server because of some error but customer handles the exception and continues making changes and those changes appears in database after transaction rollback on TransactionScope disposing. Maybe it is your case that you couldn't reproduce

(Jan 18 at 04:26) Alexey Kulakov Alexey%20Kulakov's gravatar image

Hi Alexey,

Here a UnitTest to reproduce the null ref in GetFieldStateMap, actually it's not the bug I wanted to reproduce !! The bug I was having is transaction rollback not properly done but I cannot reproduce it because I have this null ref !

using System;
using System.Data.Common;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Xtensive.Orm;
using Xtensive.Orm.Configuration;

namespace UnitTests.Orm
{
  [TestClass]
  public class DataObjects2
  {
    private const int MaxEntities = 10;
    private Domain domain;
    [TestMethod, TestCategory("SessionOptions.NotTransactionRead")]
    public void TestTransactionRollbackOnDeadLock()
    {
      domain = CreateDomain(SessionOptions.ValidateEntities | SessionOptions.AutoActivation | SessionOptions.AutoSaveChanges | SessionOptions.NonTransactionalReads);

      CreateEntities();
      Task task1 = Task.Factory.StartNew(() => UpdateEntities(1));
      Task task2 = Task.Factory.StartNew(() => UpdateEntities(2));
      Task.WaitAll(task1, task2);

      domain.Dispose();
    }

    private void CreateEntities()
    {
      using (Session session = domain.OpenSession())
      {
        using (TransactionScope t = session.OpenTransaction())
        {
          for (int i = 0; i < MaxEntities; i++)
          {
            new TestEntity() {Index = i, Value=1};
          }
          t.Complete();
        }
      }

      using (Session session = domain.OpenSession())
      {
        using (TransactionScope t = session.OpenTransaction())
        {
          Assert.IsTrue(Query.All<TestEntity>().Count() == MaxEntities);
        }
      }
    }

    private void UpdateEntities(int instanceId)
    {

      for (int i = 0; i < MaxEntities; i++)
      {
        using (Session session = domain.OpenSession())
        {
          int retryCount = 3;
          for (int retry = 0;; retry++)
          {
            int initialValue = 0;
            try
            {
              initialValue = GetEntityValue(session, i);
              UpdateEntity(session, i);
              break;
            }
            catch (Exception ex)
            {
              if (ex is DeadlockException ||
                  ex is TransactionSerializationFailureException ||
                  (ex is TargetInvocationException && (ex.InnerException is DeadlockException || ex.InnerException is TransactionSerializationFailureException)))
              {
                if (retry + 1 < retryCount)
                {
                  Debug.WriteLine("Deadlock detected : retrying transactional method for UpdateEntities({0}, {1})", instanceId, i);
                  int currentValue = GetEntityValue(session, i);
                  if (currentValue != initialValue)
                  {
                    Debug.WriteLine("Deadlock detected : retrying transactional method for UpdateEntities({0}, {1})", instanceId, i);

                  }
                  continue;

                }
                else
                {
                  Debug.WriteLine("Deadlock detected on last try : giving up on UpdateEntities2({0})", i);
                  throw;
                }
              }
              else
              {
                throw;
              }
            }
          }
        }
      }
    }

    private int GetEntityValue(Session session, int i)
    {
      int initialValue;
      using (TransactionScope t = session.OpenTransaction())
      {
        TestEntity entity = Query.All<TestEntity>().Single(e => e.Index == i);
        initialValue = entity.Value;
        t.Complete();
      }
      return initialValue;
    }

    private void UpdateEntity(Session session, int i)
    {
      using (TransactionScope t = session.OpenTransaction())
      {
        TestEntity entity = Query.All<TestEntity>().Single(e => e.Index == i);
        int initialValue = entity.Value;
        entity.Value ++;
        Debug.WriteLine("Updated entity {0} value from {1} to {2}", i, initialValue, entity.Value);
        t.Complete(); // rollback
      }
    }

    private Domain CreateDomain(SessionOptions sessionOptions)
    {
      string connectionString = Configuration.Instance.DataObjectsConnectionString;

      DomainConfiguration config = new DomainConfiguration(connectionString);
      config.UpgradeMode = DomainUpgradeMode.Recreate;
      config.Types.Register(typeof(TestEntity));

      SessionConfiguration defaultSessionConfig = config.Sessions.Default;
      if (defaultSessionConfig == null)
      {
        defaultSessionConfig = new SessionConfiguration(WellKnown.Sessions.Default);
        config.Sessions.Add(defaultSessionConfig);
      }

      defaultSessionConfig.Options = sessionOptions;
      ConnectionInfo connectionInfo = new ConnectionInfo(connectionString);
      string sqlConnectionString = new Xtensive.Sql.Drivers.SqlServer.DriverFactory().GetConnectionString(connectionInfo);
      using (System.Data.SqlClient.SqlConnection connection = new System.Data.SqlClient.SqlConnection(sqlConnectionString))
      using (DbCommand command = connection.CreateCommand())
      {
        connection.Open();
        command.CommandText = "Select * From sys.fulltext_catalogs";
        bool ftCatalogExists = false;
        using (DbDataReader reader = command.ExecuteReader())
        {
          ftCatalogExists = reader.HasRows;
        }

        if (!ftCatalogExists)
        {
          // full text catalog does not exists : creates it
          command.CommandText = "CREATE FULLTEXT CATALOG [Default] " + "WITH ACCENT_SENSITIVITY = ON " + "AS DEFAULT " + "AUTHORIZATION [dbo]";
          command.ExecuteNonQuery();

          command.CommandText = "ALTER FULLTEXT CATALOG [Default] REBUILD ";
          command.ExecuteNonQuery();
        }
      }
      return Domain.Build(config);
    }

    [Serializable]
    [HierarchyRoot]
    public class TestEntity : Entity
    {
      [Field, Key]
      public long Id { get; private set; }

      [Field]
      public int Index { get; set; }

      [Field]
      public int Value { get; set; }
    }
  }
}

answered Sep 21 '16 at 09:05

Benoit%20Nesme's gravatar image

Benoit Nesme
43192024

Your answer
Please start posting your answer anonymously - your answer will be saved within the current session and published after you log in or create a new account. Please try to give a substantial answer, for discussions, please use comments and please do remember to vote (after you log in)!
toggle preview

Subscription:

Once you sign in you will be able to subscribe for any updates here

Tags:

×4

Asked: Aug 24 '16 at 07:08

Seen: 4,318 times

Last updated: Jan 18 at 04:26

powered by OSQA