在磁盘上存储thrift-serialized对象

时间:2017-01-17 19:13:23

标签: scala serialization binary thrift

要求

  • 我需要将一个Thrift序列化对象流存储在一个文件中,以便我以后可以读取该文件并获取反序列化的对象。
  • 对象可以是不同类型的。

问题

(i)分隔文件中每个对象的最佳方法是什么。例如,在文本文件中,我可以使用换行符分隔每个对象。这种方法对二进制文件也有效吗?

(ii)为了标记每个对象的类型(在反序列化期间使用),我计划在每个字节序列的开头添加一个类型字段。有更好的方法吗?

1 个答案:

答案 0 :(得分:1)

最重要的问题是您打算如何访问该文件:顺序访问还是随机访问?

顺序访问(排序)或少数数据

  

分隔文件中每个对象的最佳方法是什么。例如,在文本文件中,我可以使用换行符分隔每个对象。这种方法对二进制文件也有效吗?

显然不是;-)。但不要担心,有一个更好的解决方案。要存储数据列表,可以简单地存储list<data>。换句话说,就像这样:

struct foo { 1: string field, 2: i32 otherfield }

list<foo>

如果数据不仅是foo,而且是不同类型的数据,请在两者之间加入一个联合:

struct foo { 1: string field, 2: i32 otherfield }

struct bar { 1: map<string,wtf> seinfield, 2: double cloverfield }

struct wtf { 1: list<double> even_more_fields }

union MyDataRecord {
  1: foo foo
  2: bar bar
  3: wtf wtf
}

list<MyDataRecord>

因为我们仍然一次读写所有内容,所以不需要人工限制。

  

要标记每个对象的类型(在反序列化期间使用),我计划在每个字节序列的开头添加一个类型字段。有更好的方法吗?

如果您将数据放入如上所述的list<>,Thrift会照顾它。您只需阅读并编写整个列表。

随机访问和/或大量数据

如果您想随机访问数据,情况会发生巨大变化。这个问题是,为了使其高效和快速 - 您需要以某种方式确定文件中给定元素的位置,而不是始终先扫描整个文件 1) 。在大多数情况下,写入的条目的字节大小会有所不同。即使它们只是一种类型foo,但仍然不能假设某个元素位于

position = sizeof(foo) *  index_of_desired_element

因为foo具有可变大小的数据成员:string字段。

要解决这个问题,我们基本上有两个选择。

(1)固定大小的记录:我们可以确保所有元素都不超过预定义的最大大小,并将其用作文件记录大小。我们也不再使用list<>,而是将数据写在文件中的正确位置。第n个元素的位置再次

position = N * predefined_record_size

显然,我们可能会浪费大量空间,而且数据量有限。

(2)索引文件:第二个选项是维护一个单独的索引文件,该文件保存数据文件中每个条目的位置。这也可以是一个简单的整数列表:

list<i32>

这里的缺点是,您需要确保索引处于正确的形状,尤其是在文件中间的插入,删除和更新操作。

上面两个选项的更普遍的问题是,特别是插入和删除操作可能会变得很痛苦,因为您可能需要移动大量数据。为了解决这个问题,您会发现自己在解决方案中添加了更多噱头,例如删除标记等。

底线

如果您只有大量数据,那么list<union>方法可能就是您要找的。由于union可以随时扩展,因此该解决方案也可以在以后添加其他元素。

如果您只想按顺序访问数据,请选择list<union>方法,或逐个读取/写入union元素。 Thrift支持Skip()功能,允许跳过不需要的数据(如果需要)。

但是,如果您想要随机访问数据和/或要处理大量数据,那么真正的数据库可能更合适。

1)扫描记录分隔符的潜在大文件不是the kind of O(?) you want