2013-08-07 34 views
5

Tôi đang viết một ứng dụng tương tác với tệp nhị phân được ánh xạ bộ nhớ lớn (10-1000 GB), giữ cơ bản một loạt các đối tượng tham chiếu với nhau. Tôi đã đưa ra một cơ chế để đọc/ghi dữ liệu này có hiệu quả, nhưng xấu xí và tiết (imo).Lưu trữ dữ liệu nhị phân có cấu trúc lớn với Haskell

Hỏi: Có cách nào thanh lịch hơn để đạt được những gì tôi đã làm không?

Tôi có một kiểu chữ cho dữ liệu có cấu trúc, với một phương pháp đọc cấu trúc thành kiểu dữ liệu Haskell (DataOpReaderT xung quanh IO).

class DBStruct a where 
    structRead :: Addr a -> DataOp a 

Để làm điều này dễ đọc hơn, tôi có một typeclass xác định những gì các thành viên cấu trúc đi nơi:

class DBStruct st => StructMem structTy valTy name | structTy name -> valTy where 
    offset :: structTy -> valTy -> name -> Int64 

Tôi có một vài chức năng helper mà sử dụng phương pháp bù đắp cho các yếu tố cấu trúc đọc/ghi, để đọc cấu trúc từ các tham chiếu được lưu trữ và để đọc chậm trễ cấu trúc đọc (để cho phép đọc toàn bộ tệp một cách lười biếng).

Vấn đề với điều này là nó liên quan đến rất nhiều sự lặp lại để sử dụng. Đối với một cấu trúc, đầu tiên tôi phải xác định kiểu Haskell:

data RowBlock = RowBlock {rbNext :: Maybe RowBlock 
         ,rbPrev :: Maybe RowBlock 
         ,rbRows :: [RowTy] 
         } 

Sau đó name loại:

data Next = Next 
data Prev = Prev 
data Count = Count 
newtype Row = Row Int64 

Sau đó, các trường hợp cho mỗi thành viên cấu trúc:

instance StructMem RowBlock (Maybe (Addr RowBlock)) Next where offset _ _ _ = 0 
instance StructMem RowBlock (Maybe (Addr RowBlock)) Prev where offset _ _ _ = 8 
instance StructMem RowBlock Int64 Count where offset _ _ _ = 16 
instance StructMem RowBlock RowTy Row where offset _ _ (Row n) = 24 + n * 8 

Sau đó, cấu trúc phương thức đọc:

instance DBStruct RowBlock where 
    structRead a = do 
     n <- elemMaybePtr a Next 
     p <- elemMaybePtr a Prev 
     c <- elemRead a Count 
     rs <- mapM (elemRead a . Row) [0 .. c-1] 
     return $ RowBlock n p rs 

Vì vậy, tất cả những gì tôi thực sự đạt được là triển khai lại các cấu trúc C theo một cách tiết kiệm hơn (và chậm). Tôi sẽ hạnh phúc hơn nếu điều này ngắn gọn hơn trong khi vẫn giữ được sự an toàn kiểu. Chắc chắn đây là một vấn đề thường gặp phải.

Một vài lựa chọn thay thế có thể tôi có thể nghĩ đến là:

  • Mương tập tin bộ nhớ ánh xạ và sử dụng Data.Binary, viết ByteStrings vào đĩa theo cách thông thường.
  • Sử dụng deriving Generic để tạo generic đọc và viết các chức năng
  • Overload Functional References
  • Do something huyền diệu với ống kính monadic.

EDIT: SSCCE as requested

+0

Bạn có thể cung cấp một ví dụ đơn giản, khép kín có thể được biên soạn, một thứ gì đó để bắt đầu không? –

+0

@ PetrPudlák Tôi có thể làm điều đó sau ngày hôm nay nếu bạn nghĩ rằng nó sẽ giúp mọi người tìm ra câu trả lời. Tuy nhiên, điều này có nghĩa là có nhiều câu hỏi về kiến ​​trúc hơn là một câu hỏi tại sao không phải là mã của tôi; mã tôi đã đăng có nghĩa là minh họa hơn kiến ​​trúc hiện tại của tôi hơn bất kỳ thứ gì khác. – Dan

+1

Có, [SSCCE] (http://www.sscce.org/) sẽ giúp tôi hiểu rõ hơn về thiết kế hiện tại của bạn. –

Trả lời

1

Bạn có thể thử sử dụng Data.Binary với PTRs của bạn.

Để viết:

Sử dụng Data.Binary để tạo ByteString. ByteString là một tuple (ForeignPtr Word8, Int, Int) chứa địa chỉ, độ lệch và độ dài nơi dữ liệu được lưu trữ. Bạn có thể sử dụng gói Data.ByteString.Internal để tớiForeignPtr, nó sẽ giải nén tuple cho bạn. Ngoại quốc.ForeignPtr cung cấp vớiForeignPtr, có một hàm thực hiện một hành động IO thông qua con trỏ. Trong đó bạn có thể memcpy (một ràng buộc cho điều này cũng được cung cấp trong Data.ByteString.Internal) lưu trữ bytestring để Ptr mmapped bạn nhận được từ mmap.

Để đọc:

Bạn có thể sử dụng fromForiegnPtr Data.ByteString.Internal để biến một PTR vào một bytestring. Đây là cơ bản những gì các thư viện mmap làm, nhưng bạn có thể làm điều đó một bản ghi tại một thời điểm thay vì với toàn bộ khu vực. Một khi bạn có một khung nhìn ByteString trên bộ nhớ, bạn có thể giải nén nó với Data.Binary.

Một tùy chọn khác là tận dụng lợi thế của thực tế là ByteString có triển khai thay thế trong Data.Vector.Storable.ByteString, cho phép bạn sử dụng giao diện Storable bạn đang sử dụng ngay bây giờ để đọc/ghi chúng vào Ptrs mmaped . Giao diện và kiểu cơ bản là đẳng cấu với Data.ByteString, nhưng nó có các cá thể Storable.

+0

Tôi cũng cần có khả năng ghi vào tệp. – Dan

Các vấn đề liên quan