2727import org .lance .spark .LanceSparkCatalogConfig ;
2828import org .lance .spark .LanceSparkWriteOptions ;
2929import org .lance .spark .function .LanceFragmentIdWithDefaultFunction ;
30+ import org .lance .spark .utils .BlobReferenceResolver ;
31+ import org .lance .spark .utils .BlobSourceContext ;
3032import org .lance .spark .utils .Utils ;
3133
3234import com .google .common .collect .ImmutableList ;
@@ -94,14 +96,18 @@ public class SparkPositionDeltaWrite implements DeltaWrite, RequiresDistribution
9496 private final boolean managedVersioning ;
9597 private final boolean hasStableRowIds ;
9698
99+ /** Blob source contexts for resolving copy tokens, keyed by source dataset URI. */
100+ private final Map <String , BlobSourceContext > blobSourceContexts ;
101+
97102 public SparkPositionDeltaWrite (
98103 StructType sparkSchema ,
99104 LanceSparkWriteOptions writeOptions ,
100105 Map <String , String > initialStorageOptions ,
101106 String namespaceImpl ,
102107 Map <String , String > namespaceProperties ,
103108 boolean managedVersioning ,
104- List <String > tableId ) {
109+ List <String > tableId ,
110+ Map <String , BlobSourceContext > blobSourceContexts ) {
105111 this .sparkSchema = sparkSchema ;
106112 try (Dataset ds = Utils .openDatasetBuilder (writeOptions ).build ()) {
107113 this .writeOptions = writeOptions .withVersion (ds .version ());
@@ -116,6 +122,7 @@ public SparkPositionDeltaWrite(
116122 this .namespaceProperties = namespaceProperties ;
117123 this .tableId = tableId ;
118124 this .managedVersioning = managedVersioning ;
125+ this .blobSourceContexts = blobSourceContexts ;
119126 }
120127
121128 @ Override
@@ -151,7 +158,8 @@ public DeltaWriterFactory createBatchWriterFactory(PhysicalWriteInfo info) {
151158 namespaceImpl ,
152159 namespaceProperties ,
153160 tableId ,
154- hasStableRowIds );
161+ hasStableRowIds ,
162+ blobSourceContexts );
155163 }
156164
157165 @ Override
@@ -251,6 +259,7 @@ private static class PositionDeltaWriteFactory implements DeltaWriterFactory {
251259 private final Map <String , String > namespaceProperties ;
252260 private final List <String > tableId ;
253261 private final boolean hasStableRowIds ;
262+ private final Map <String , BlobSourceContext > blobSourceContexts ;
254263
255264 PositionDeltaWriteFactory (
256265 StructType sparkSchema ,
@@ -259,34 +268,44 @@ private static class PositionDeltaWriteFactory implements DeltaWriterFactory {
259268 String namespaceImpl ,
260269 Map <String , String > namespaceProperties ,
261270 List <String > tableId ,
262- boolean hasStableRowIds ) {
271+ boolean hasStableRowIds ,
272+ Map <String , BlobSourceContext > blobSourceContexts ) {
263273 this .sparkSchema = sparkSchema ;
264274 this .writeOptions = writeOptions ;
265275 this .initialStorageOptions = initialStorageOptions ;
266276 this .namespaceImpl = namespaceImpl ;
267277 this .namespaceProperties = namespaceProperties ;
268278 this .tableId = tableId ;
269279 this .hasStableRowIds = hasStableRowIds ;
280+ this .blobSourceContexts = blobSourceContexts ;
270281 }
271282
272283 @ Override
273284 public DeltaWriter <InternalRow > createWriter (int partitionId , long taskId ) {
274285 int batchSize = writeOptions .getBatchSize ();
275286 boolean useQueuedBuffer = writeOptions .isUseQueuedWriteBuffer ();
276287 boolean useLargeVarTypes = writeOptions .isUseLargeVarTypes ();
288+ long maxBatchBytes = writeOptions .getMaxBatchBytes ();
277289
278290 LanceSparkWriteOptions fragmentWriteOptions =
279291 writeOptions .toBuilder ().enableStableRowIds (false ).build ();
280292 WriteParams params = fragmentWriteOptions .toWriteParams (initialStorageOptions );
281293
294+ // One resolver per write task, closed via LanceDataWriter when the task finishes. Always
295+ // created so copy tokens resolve even without captured contexts (falls back to open-by-URI).
296+ BlobReferenceResolver blobResolver = new BlobReferenceResolver (blobSourceContexts );
297+
282298 // Select buffer type based on configuration
283299 ArrowBatchWriteBuffer writeBuffer ;
284300 if (useQueuedBuffer ) {
285301 int queueDepth = writeOptions .getQueueDepth ();
286302 writeBuffer =
287- new QueuedArrowBatchWriteBuffer (sparkSchema , batchSize , queueDepth , useLargeVarTypes );
303+ new QueuedArrowBatchWriteBuffer (
304+ sparkSchema , batchSize , queueDepth , useLargeVarTypes , maxBatchBytes , blobResolver );
288305 } else {
289- writeBuffer = new SemaphoreArrowBatchWriteBuffer (sparkSchema , batchSize , useLargeVarTypes );
306+ writeBuffer =
307+ new SemaphoreArrowBatchWriteBuffer (
308+ sparkSchema , batchSize , useLargeVarTypes , maxBatchBytes , blobResolver );
290309 }
291310
292311 // Create fragment in background thread
@@ -305,7 +324,8 @@ public DeltaWriter<InternalRow> createWriter(int partitionId, long taskId) {
305324
306325 return new LanceDeltaWriter (
307326 writeOptions ,
308- new LanceDataWriter (writeBuffer , fragmentCreationTask , fragmentCreationThread ),
327+ new LanceDataWriter (
328+ writeBuffer , fragmentCreationTask , fragmentCreationThread , null , null , blobResolver ),
309329 initialStorageOptions ,
310330 hasStableRowIds );
311331 }
0 commit comments