【问题标题】:Prepared statement caching issue in Cassandra Csharp driverCassandra Csharp 驱动程序中的预处理语句缓存问题
【发布时间】:2016-04-09 07:57:22
【问题描述】:

我相信我在 Cassandra csharp 驱动程序(版本 2.7.3)的 StatementFactory 中缓存准备语句的逻辑上发现了一个错误。这是用例。

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));

我们发现运行这个删除后,只有第一个请求成功。深入了解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;
            });
    }

可以看到缓存只使用了cql语句。在我们的例子中,我们在不同的键空间(又名会话)中有相同的表名。我们在两个查询中的 cql 语句看起来是一样的。即 DELETE FROM foo_bar WHERE id =?.

如果我不得不猜测,我会说一个简单的解决方法是将 cql 语句和键空间组合在一起作为缓存键。

以前有没有其他人遇到过这个问题?

【问题讨论】:

    标签: c# caching cassandra datastax opscenter


    【解决方案1】:

    作为一个简单的解决方法,我使用 DoNotPrepare 跳过缓存

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

    我还发现了Datastax 的一个未解决问题

    【讨论】:

      【解决方案2】:

      有一个open ticket to fix this behaviour

      作为一种解决方法,您可以在创建Mapper 时使用不同的MappingConfiguration 实例:

      ISession session1 = cluster.Connect("ks1");
      ISession session2 = cluster.Connect("ks2");
      
      IMapper mapper1 = new Mapper(session1, new MappingConfiguration());
      IMapper mapper2 = new Mapper(session2, new MappingConfiguration());
      

      或者,您可以重用单个 ISession 实例并完全限定您的查询以包含键空间。

      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);
      

      【讨论】:

        猜你喜欢
        • 2013-05-30
        • 2015-06-23
        • 2017-07-01
        • 2016-04-29
        • 1970-01-01
        • 2020-09-28
        • 2016-10-02
        • 1970-01-01
        • 2019-08-01
        相关资源
        最近更新 更多