Prepared statement caching issue in Cassandra Csharp driver

孤者浪人 提交于 2019-12-04 04:02:44

问题


I believe I have found a bug with the logic of how a prepared statement is cached in the StatementFactory in the Cassandra csharp driver (version 2.7.3). Here is the use case.

Guid key = Guid.NewGuid(); // your key

ISession session_foo = new Session("foo"); //This is pseudo code
ISession session_bar = new Session("bar");

var foo_mapper = new Mapper(session_foo); //table foo_bar
var bar_mapper = new Mapper(session_bar); //table foo_bar

await Task.WhenAll(
   foo_mapper.DeleteAsync<Foo>("WHERE id = ?", key),
   bar_mapper.DeleteAsync<Bar>("WHERE id = ?", key));

We have found that after running this deletes, only the first request is succeeding. After diving in the the source code of StatementFactory

public Task<Statement> GetStatementAsync(ISession session, Cql cql)
    {
        if (cql.QueryOptions.NoPrepare)
        {
            // Use a SimpleStatement if we're not supposed to prepare
            Statement statement = new SimpleStatement(cql.Statement, cql.Arguments);
            SetStatementProperties(statement, cql);
            return TaskHelper.ToTask(statement);
        }
        return _statementCache
            .GetOrAdd(cql.Statement, session.PrepareAsync)
            .Continue(t =>
            {
                if (_statementCache.Count > MaxPreparedStatementsThreshold)
                {
                    Logger.Warning(String.Format("The prepared statement cache contains {0} queries. Use parameter markers for queries. You can configure this warning threshold using MappingConfiguration.SetMaxStatementPreparedThreshold() method.", _statementCache.Count));
                }
                Statement boundStatement = t.Result.Bind(cql.Arguments);
                SetStatementProperties(boundStatement, cql);
                return boundStatement;
            });
    }

You can see that the cache only uses the cql statement. In our case, we have the same table names in different keyspaces (aka sessions). Our cql statement in both queries look the same. ie DELETE FROM foo_bar WHERE id =?.

If I had to guess, I would say that a simple fix would be to combine the cql statement and keyspace together as the cache key.

Has anyone else run into this issue before?


回答1:


As a simple workaround, I am skipping the cache by using the DoNotPrepare

await _mapper.DeleteAsync<Foo>(Cql.New("WHERE id = ?", key).WithOptions(opt => opt.DoNotPrepare()));

I also found an open issue with Datastax




回答2:


There is an open ticket to fix this behaviour.

As a workaround, you can use a different MappingConfiguration instances when creating the Mapper:

ISession session1 = cluster.Connect("ks1");
ISession session2 = cluster.Connect("ks2");

IMapper mapper1 = new Mapper(session1, new MappingConfiguration());
IMapper mapper2 = new Mapper(session2, new MappingConfiguration());

Or, you can reuse a single ISession instance and fully-qualify your queries to include the keyspace.

MappingConfiguration.Global.Define(
   new Map<Foo>()
      .TableName("foo")
      .KeyspaceName("ks1"),
   new Map<Bar>()
      .TableName("bar")
      .KeyspaceName("ks2"));

ISession session = cluster.Connect();
IMapper mapper = new Mapper(session);


来源:https://stackoverflow.com/questions/34612595/prepared-statement-caching-issue-in-cassandra-csharp-driver

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!