如何在Cassandra c#驱动程序中存储分页状态?

时间:2017-11-11 14:41:04

标签: c# datastax-enterprise cassandra-3.0

我已经阅读了几个使用Cassandra c#driver实现手动分页的链接。

链接提及:

Backward paging in cassandra c# driver

https://datastax.github.io/csharp-driver/features/paging/

我的要求:

我正在尝试获取表格中所有不同分区键的列表,这个表格太大了。

由于大小,Cassandra db在检索它们或首次执行查询时会抛出错误。现在假设在获取100000个不同的分区键后它失败了,我将使用Cassandra c#driver提供的分页状态。

现在我在未能记录文件之前保存最后一个可用的页面状态,并再次使用它以从失败的地方继续。

我使用以下方法将分页状态保存到日志文件中:

Encoding.ASCII.GetString(pagingState);

使用以下方法检索表单日志文件:

Encoding.ASCII.GetBytes(pagingState);

但是当我将它传递给 .SetPagingState(pagingState)并执行查询时,它会抛出异常,如:

  

java.lang.IllegalStateException:无法调用hasNext()直到   之前的迭代器已被完全消耗

我在保存到文件之前和从文件中检索之后比较逐字节数组字节。字节数组中的几个值不同。 我尝试使用UIF8编码,但没有用。

注意: 当我在没有转换的情况下传递字节数组时,它的工作正常。我的意思是下面的条件代码完美无缺。

if (pagingState != null)
{
     GenerateInitialLogs(pagingState);
}

完整功能:

    private void BtnGetPrimaryKeys_Click(object sender, EventArgs e)
    {
        string fileContent = File.ReadAllText("D:/Logs/log.txt");            
        if(fileContent.Length > 0)
        {
            GenerateInitialLogs(Encoding.ASCII.GetBytes(fileContent));
        }
        else
        {
            GenerateInitialLogs(null);
        }
    }

    private void Log(byte[] pagingState)
    {
        File.WriteAllText("D:/Logs/log.txt", Encoding.ASCII.GetString(pagingState));    
    }

    private int GenerateInitialLogs(byte[] pagingState)
    {            
        try
        {
            RowSet rowSet = BLL.SelectDistinctPrimaryKeys(pagingState);

            List<PrimaryKey> distinctPrimaryKeys = new List<PrimaryKey>();
            foreach (Row row in rowSet)
            {
                if (rowSet.PagingState != null) { pagingState = new byte[rowSet.PagingState.Length]; }
                pagingState = rowSet.PagingState;
            }
            Log(pagingState)

            if (pagingState != null)
            {
                GenerateInitialLogs(pagingState);
            }
        }
        catch(Exception ex)
        {
            throw ex;
        }
    }

    public static RowSet SelectDistinctPrimaryKeysFromTagReadings(byte[] pagingState)
    {
        try
        {
            // will execute on continuing after failing in between. 
            if (pagingState != null)
            {
                PreparedStatement preparedStatement = BLL.currentSession.Prepare("SELECT DISTINCT \"Url\",\"Id\" FROM \"Readings\" ");
                BoundStatement boundStatement = preparedStatement.Bind();
                IStatement istatement = boundStatement.SetAutoPage(false).SetPageSize(1000).SetPagingState(pagingState);
                return BLL.currentSession.Execute(istatement);
            }
            else
            {
                PreparedStatement preparedStatement = BLL.currentSession.Prepare("SELECT DISTINCT \"Url\",\"Id\" FROM \"Readings\" ");
                BoundStatement boundStatement = preparedStatement.Bind();
                IStatement istatement = boundStatement.SetAutoPage(false).SetPageSize(1000);
                return BLL.currentSession.Execute(istatement);                    
            }
        }
        catch (Exception ex)
        {
            throw ex;
        }
    }

2 个答案:

答案 0 :(得分:2)

我没想到这个解决方案。它由Jorge Bay Gondra(datastax的员工)完成。

原始回答:

https://groups.google.com/a/lists.datastax.com/forum/#!topic/csharp-driver-user/4XWTXZC-hyI

<强>解决方案:

无法将它们转换为ASCII或UIF8或任何编码,因为它们不代表文本。

使用这些函数将字节数组转换为十六进制,反之亦然。

public static string ByteArrayToHexaDecimalString(byte[] bytes)
{
     StringBuilder stringBuilder = new StringBuilder(bytes.Length * 2);
     foreach (byte b in bytes) { stringBuilder.AppendFormat("{0:x2}", b); }
     return stringBuilder.ToString();
}

public static byte[] HexaDecimalStringToByteArray(String hexaDecimalString)
{
     int NumberChars = hexaDecimalString.Length;
     byte[] bytes = new byte[NumberChars / 2];
     for (int i = 0; i < NumberChars; i += 2)
     { 
         bytes[i / 2] = Convert.ToByte(hexaDecimalString.Substring(i, 2), 16); 
     }
     return bytes;
}

答案 1 :(得分:0)

我还发现Encoding.UTF8.GetString和GetBytes并非在所有情况下都起作用,尽管在某些情况下也可以,但是发现Convert.ToBase64String和相反的方法可以正常工作。

public static string ConvertPagingStateToString(byte[] pagingState) 
     => Convert.ToBase64String(pagingState);

public static byte[] ConvertStringToPagingState(string pagingStateString) 
     => Convert.FromBase64String(pagingStateString);