3232PROPERTY_REFERENCED_DATA_FILE = "referenced-data-file"
3333
3434
35- def _deserialize_bitmap (pl : bytes ) -> list [BitMap ]:
36- number_of_bitmaps = int .from_bytes (pl [0 :8 ], byteorder = "little" )
37- pl = pl [8 :]
38-
39- bitmaps = []
40- last_key = - 1
41- for _ in range (number_of_bitmaps ):
42- key = int .from_bytes (pl [0 :4 ], byteorder = "little" )
43- if key < 0 :
44- raise ValueError (f"Invalid unsigned key: { key } " )
45- if key <= last_key :
46- raise ValueError ("Keys must be sorted in ascending order" )
47- if key > MAX_JAVA_SIGNED :
48- raise ValueError (f"Key { key } is too large, max { MAX_JAVA_SIGNED } to maintain compatibility with Java impl" )
49- pl = pl [4 :]
50-
51- while last_key < key - 1 :
52- bitmaps .append (EMPTY_BITMAP )
53- last_key += 1
54-
55- bm = BitMap ().deserialize (pl )
56- # TODO: Optimize this
57- pl = pl [len (bm .serialize ()) :]
58- bitmaps .append (bm )
59-
60- last_key = key
61-
62- return bitmaps
63-
64-
6535class PuffinBlobMetadata (IcebergBaseModel ):
6636 type : Literal ["deletion-vector-v1" ] = Field ()
6737 fields : list [int ] = Field ()
@@ -78,15 +48,9 @@ class Footer(IcebergBaseModel):
7848 properties : dict [str , str ] = Field (default_factory = dict )
7949
8050
81- def _bitmaps_to_chunked_array (bitmaps : list [BitMap ]) -> "pa.ChunkedArray" :
82- import pyarrow as pa
83-
84- return pa .chunked_array ([(key_pos << 32 ) + pos for pos in bitmap ] for key_pos , bitmap in enumerate (bitmaps ))
85-
86-
8751class PuffinFile :
8852 footer : Footer
89- _deletion_vectors : dict [ str , list [ BitMap ]]
53+ _payload : bytes
9054
9155 def __init__ (self , puffin : bytes ) -> None :
9256 for magic_bytes in [puffin [:4 ], puffin [- 4 :]]:
@@ -105,12 +69,56 @@ def __init__(self, puffin: bytes) -> None:
10569 footer_payload_size_int = int .from_bytes (puffin [- 12 :- 8 ], byteorder = "little" )
10670
10771 self .footer = Footer .model_validate_json (puffin [- (footer_payload_size_int + 12 ) : - 12 ])
108- puffin = puffin [8 :]
72+ self . _payload = puffin [8 :]
10973
74+ def get_blob_payload (self , blob : PuffinBlobMetadata ) -> bytes :
75+ return self ._payload [blob .offset : blob .offset + blob .length ]
76+
77+
78+ class DeletionVector :
79+ _deletion_vectors : dict [str , list [BitMap ]]
80+
81+ def __init__ (self , puffin_file : PuffinFile ) -> None :
11082 self ._deletion_vectors = {
111- blob .properties [PROPERTY_REFERENCED_DATA_FILE ]: _deserialize_bitmap (puffin [ blob . offset : blob . offset + blob . length ] )
112- for blob in self .footer .blobs
83+ blob .properties [PROPERTY_REFERENCED_DATA_FILE ]: self . _deserialize_bitmap (puffin_file . get_blob_payload ( blob ) )
84+ for blob in puffin_file .footer .blobs
11385 }
11486
87+ @staticmethod
88+ def _deserialize_bitmap (pl : bytes ) -> list [BitMap ]:
89+ number_of_bitmaps = int .from_bytes (pl [0 :8 ], byteorder = "little" )
90+ pl = pl [8 :]
91+
92+ bitmaps = []
93+ last_key = - 1
94+ for _ in range (number_of_bitmaps ):
95+ key = int .from_bytes (pl [0 :4 ], byteorder = "little" )
96+ if key < 0 :
97+ raise ValueError (f"Invalid unsigned key: { key } " )
98+ if key <= last_key :
99+ raise ValueError ("Keys must be sorted in ascending order" )
100+ if key > MAX_JAVA_SIGNED :
101+ raise ValueError (f"Key { key } is too large, max { MAX_JAVA_SIGNED } to maintain compatibility with Java impl" )
102+ pl = pl [4 :]
103+
104+ while last_key < key - 1 :
105+ bitmaps .append (EMPTY_BITMAP )
106+ last_key += 1
107+
108+ bm = BitMap ().deserialize (pl )
109+ # TODO: Optimize this
110+ pl = pl [len (bm .serialize ()) :]
111+ bitmaps .append (bm )
112+
113+ last_key = key
114+
115+ return bitmaps
116+
117+ @staticmethod
118+ def _bitmaps_to_chunked_array (bitmaps : list [BitMap ]) -> "pa.ChunkedArray" :
119+ import pyarrow as pa
120+
121+ return pa .chunked_array ([(key_pos << 32 ) + pos for pos in bitmap ] for key_pos , bitmap in enumerate (bitmaps ))
122+
115123 def to_vector (self ) -> dict [str , "pa.ChunkedArray" ]:
116- return {path : _bitmaps_to_chunked_array (bitmaps ) for path , bitmaps in self ._deletion_vectors .items ()}
124+ return {path : self . _bitmaps_to_chunked_array (bitmaps ) for path , bitmaps in self ._deletion_vectors .items ()}
0 commit comments