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

How to store paging state in Cassandra c# driver?

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

引用的链接:

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

我的要求:

我正在尝试获取所有不同分区键的列表 table,但它的大小太大了。

由于 Cassandra 数据库的大小,在检索它们之间或第一次执行查询时抛出错误。现在假设它在获取 100000 个不同的分区键后失败,我将使用 Cassandra c# 驱动程序提供的分页状态。

现在我正在保存日志文件失败之前的最后可用页面状态,并再次使用它从失败的地方继续。

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

Encoding.ASCII.GetString(pagingState);

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

Encoding.ASCII.GetBytes(pagingState);

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

java.lang.IllegalStateException: Cannot call hasNext() until the previous iterator has been fully consumed

我在保存到文件之前和从文件中检索它们之后逐字节数组字节进行了比较。字节数组中的几个值是不同的。 我尝试使用 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;
        }
    }

这个解决办法不是我想出来的。它由 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;
}

我还发现 Encoding.UTF8.GetString 和 GetBytes 并非在所有情况下都有效,虽然对某些情况下有效,但发现 Convert.ToBase64String 和相反的情况下可以正常工作。

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

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