1515
1616import pyarrow
1717from orso .schema import RelationSchema
18+ from orso .tools import single_item_cache
1819from orso .types import OrsoTypes
1920
2021from opteryx .connectors .base .base_connector import BaseConnector
2122from opteryx .connectors .capabilities import LimitPushable
2223from opteryx .connectors .capabilities import Partitionable
2324from opteryx .connectors .capabilities import PredicatePushable
25+ from opteryx .connectors .capabilities import Statistics
2426from opteryx .exceptions import DataError
2527from opteryx .exceptions import DatasetNotFoundError
2628from opteryx .exceptions import EmptyDatasetError
4648 mmap_config ["access" ] = mmap .ACCESS_READ
4749
4850
49- def read_blob (
50- * , blob_name : str , decoder , statistics , just_schema = False , projection = None , selection = None
51- ):
52- """
53- Read a blob (binary large object) from disk using memory-mapped file access.
54-
55- This method uses low-level file reading with memory-mapped files to
56- improve performance. It reads the entire file into memory and then
57- decodes it using the provided decoder function.
58-
59- Parameters:
60- blob_name (str):
61- The name of the blob file to read.
62- decoder (callable):
63- A function to decode the memory-mapped file content.
64- just_schema (bool, optional):
65- If True, only the schema of the data is returned. Defaults to False.
66- projection (list, optional):
67- A list of fields to project. Defaults to None.
68- selection (dict, optional):
69- A dictionary of selection criteria. Defaults to None.
70- **kwargs:
71- Additional keyword arguments.
72-
73- Returns:
74- The decoded blob content.
75-
76- Raises:
77- FileNotFoundError:
78- If the blob file does not exist.
79- OSError:
80- If an I/O error occurs while reading the file.
81- """
82- try :
83- file_descriptor = os .open (blob_name , os .O_RDONLY | os .O_BINARY )
84- if hasattr (os , "posix_fadvise" ):
85- os .posix_fadvise (file_descriptor , 0 , 0 , os .POSIX_FADV_WILLNEED )
86- size = os .fstat (file_descriptor ).st_size
87- _map = mmap .mmap (file_descriptor , length = size , ** mmap_config )
88- result = decoder (
89- _map ,
90- just_schema = just_schema ,
91- projection = projection ,
92- selection = selection ,
93- use_threads = True ,
94- )
95- statistics .bytes_read += size
96- return result
97- finally :
98- os .close (file_descriptor )
99-
100-
101- class DiskConnector (BaseConnector , Partitionable , PredicatePushable , LimitPushable ):
51+ class DiskConnector (BaseConnector , Partitionable , PredicatePushable , LimitPushable , Statistics ):
10252 """
10353 Connector for reading datasets from files on local storage.
10454 """
@@ -137,13 +87,74 @@ def __init__(self, **kwargs):
13787 Partitionable .__init__ (self , ** kwargs )
13888 PredicatePushable .__init__ (self , ** kwargs )
13989 LimitPushable .__init__ (self , ** kwargs )
90+ Statistics .__init__ (self , ** kwargs )
14091
14192 self .dataset = self .dataset .replace ("." , OS_SEP )
14293 self .cached_first_blob = None # Cache for the first blob in the dataset
14394 self .blob_list = {}
14495 self .rows_seen = 0
14596 self .blobs_seen = 0
14697
98+ def read_blob (
99+ self , * , blob_name : str , decoder , just_schema = False , projection = None , selection = None
100+ ):
101+ """
102+ Read a blob (binary large object) from disk using memory-mapped file access.
103+
104+ This method uses low-level file reading with memory-mapped files to
105+ improve performance. It reads the entire file into memory and then
106+ decodes it using the provided decoder function.
107+
108+ Parameters:
109+ blob_name (str):
110+ The name of the blob file to read.
111+ decoder (callable):
112+ A function to decode the memory-mapped file content.
113+ just_schema (bool, optional):
114+ If True, only the schema of the data is returned. Defaults to False.
115+ projection (list, optional):
116+ A list of fields to project. Defaults to None.
117+ selection (dict, optional):
118+ A dictionary of selection criteria. Defaults to None.
119+ **kwargs:
120+ Additional keyword arguments.
121+
122+ Returns:
123+ The decoded blob content.
124+
125+ Raises:
126+ FileNotFoundError:
127+ If the blob file does not exist.
128+ OSError:
129+ If an I/O error occurs while reading the file.
130+ """
131+ try :
132+ file_descriptor = os .open (blob_name , os .O_RDONLY | os .O_BINARY )
133+ if hasattr (os , "posix_fadvise" ):
134+ os .posix_fadvise (file_descriptor , 0 , 0 , os .POSIX_FADV_WILLNEED )
135+ size = os .fstat (file_descriptor ).st_size
136+ _map = mmap .mmap (file_descriptor , length = size , ** mmap_config )
137+ result = decoder (
138+ _map ,
139+ just_schema = just_schema ,
140+ projection = projection ,
141+ selection = selection ,
142+ use_threads = True ,
143+ )
144+ self .statistics .bytes_read += size
145+
146+ if not just_schema :
147+ stats = self .read_blob_statistics (
148+ blob_name = blob_name , blob_bytes = _map , decoder = decoder
149+ )
150+ if self .relation_statistics is None :
151+ self .relation_statistics = stats
152+
153+ return result
154+ finally :
155+ os .close (file_descriptor )
156+
157+ @single_item_cache
147158 def get_list_of_blob_names (self , * , prefix : str ) -> List [str ]:
148159 """
149160 List all blob files in the given directory path.
@@ -190,15 +201,19 @@ def read_dataset(
190201 prefix = self .dataset ,
191202 )
192203
204+ if predicates is not None :
205+ blob_names = self .prune_blobs (
206+ blob_names = blob_names , query_statistics = self .statistics , selection = predicates
207+ )
208+
193209 remaining_rows = limit if limit is not None else float ("inf" )
194210
195211 for blob_name in blob_names :
196212 decoder = get_decoder (blob_name )
197213 try :
198214 if not just_schema :
199- num_rows , _ , decoded = read_blob (
215+ num_rows , _ , decoded = self . read_blob (
200216 blob_name = blob_name ,
201- statistics = self .statistics ,
202217 decoder = decoder ,
203218 just_schema = False ,
204219 projection = columns ,
@@ -219,9 +234,8 @@ def read_dataset(
219234 if remaining_rows <= 0 :
220235 break
221236 else :
222- schema = read_blob (
237+ schema = self . read_blob (
223238 blob_name = blob_name ,
224- statistics = self .statistics ,
225239 decoder = decoder ,
226240 just_schema = True ,
227241 )
0 commit comments