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
1391316

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
45215

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
1391316

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: 2,718 times

Last updated: Sep 21 '16 at 09:05

powered by OSQA