SDDS ToolKit Programs and Libraries for C and Python
Loading...
Searching...
No Matches
SDDS_MPI_binary.c
Go to the documentation of this file.
1/**
2 * @file SDDS_MPI_binary.c
3 * @brief Implementation of SDDS MPI Functions
4 *
5 * This source file contains the implementation of functions responsible for reading
6 * SDDS (Self Describing Data Set) datasets in binary format using MPI (Message Passing Interface).
7 * It handles both native and non-native byte orders, ensuring compatibility across different
8 * machine architectures. The functions manage buffer operations, memory allocation, and MPI
9 * communication to facilitate efficient and accurate data retrieval in parallel processing environments.
10 *
11 * @copyright
12 * - (c) 2002 The University of Chicago, as Operator of Argonne National Laboratory.
13 * - (c) 2002 The Regents of the University of California, as Operator of Los Alamos National Laboratory.
14 *
15 * @license
16 * This file is distributed under the terms of the Software License Agreement
17 * found in the file LICENSE included with this distribution.
18 *
19 * @authors
20 * H. Shang
21 * M. Borland
22 * R. Soliday
23 */
24
25#include "mdb.h"
26#include "mdb_thread.h"
27#include "SDDS.h"
28
29static MDB_THREAD_LOCK defaultStringLengthLock = MDB_THREAD_LOCK_INITIALIZER;
30static int32_t defaultStringLength = SDDS_MPI_STRING_COLUMN_LEN;
31
32static MDB_THREAD_LOCK defaultTitleBufferSizeLock = MDB_THREAD_LOCK_INITIALIZER;
33static int32_t defaultTitleBufferSize = 2400000;
34
35static MDB_THREAD_LOCK defaultReadBufferSizeLock = MDB_THREAD_LOCK_INITIALIZER;
36static int32_t defaultReadBufferSize = 4000000;
37
38static MDB_THREAD_LOCK defaultWriteBufferSizeLock = MDB_THREAD_LOCK_INITIALIZER;
39static int32_t defaultWriteBufferSize = 0;
40
41static MDB_THREAD_LOCK number_of_string_truncated_lock = MDB_THREAD_LOCK_INITIALIZER;
42static int32_t number_of_string_truncated = 0;
43
44static MDB_THREAD_LOCK SDDS_MPI_write_kludge_usleep_lock = MDB_THREAD_LOCK_INITIALIZER;
45static long SDDS_MPI_write_kludge_usleep = 0;
46
47static MDB_THREAD_LOCK SDDS_MPI_force_file_sync_lock = MDB_THREAD_LOCK_INITIALIZER;
48static short SDDS_MPI_force_file_sync = 0;
49
50static int32_t SDDS_GetLockedDefaultStringLength(void) {
51 int32_t length;
52 mdb_thread_lock(&defaultStringLengthLock);
53 length = defaultStringLength;
54 mdb_thread_unlock(&defaultStringLengthLock);
55 return length;
56}
57
58static int32_t SDDS_GetLockedDefaultTitleBufferSize(void) {
59 int32_t size;
60 mdb_thread_lock(&defaultTitleBufferSizeLock);
61 size = defaultTitleBufferSize;
62 mdb_thread_unlock(&defaultTitleBufferSizeLock);
63 return size;
64}
65
66static int32_t SDDS_GetLockedDefaultReadBufferSize(void) {
67 int32_t size;
68 mdb_thread_lock(&defaultReadBufferSizeLock);
69 size = defaultReadBufferSize;
70 mdb_thread_unlock(&defaultReadBufferSizeLock);
71 return size;
72}
73
74static int32_t SDDS_GetLockedDefaultWriteBufferSize(void) {
75 int32_t size;
76 mdb_thread_lock(&defaultWriteBufferSizeLock);
77 size = defaultWriteBufferSize;
78 mdb_thread_unlock(&defaultWriteBufferSizeLock);
79 return size;
80}
81
82static long SDDS_MPI_GetLockedWriteKludgeUsleep(void) {
83 long value;
84 mdb_thread_lock(&SDDS_MPI_write_kludge_usleep_lock);
85 value = SDDS_MPI_write_kludge_usleep;
86 mdb_thread_unlock(&SDDS_MPI_write_kludge_usleep_lock);
87 return value;
88}
89
90static short SDDS_MPI_GetLockedForceFileSync(void) {
91 short value;
92 mdb_thread_lock(&SDDS_MPI_force_file_sync_lock);
93 value = SDDS_MPI_force_file_sync;
94 mdb_thread_unlock(&SDDS_MPI_force_file_sync_lock);
95 return value;
96}
97
98#if MPI_DEBUG
99static FILE *fpdeb = NULL;
100#endif
101
102/**
103 * @brief Set the default read buffer size for SDDS.
104 *
105 * This function updates the default buffer size used for reading SDDS binary data.
106 *
107 * @param newSize The new buffer size to set. Must be greater than zero.
108 * If newSize is less than or equal to zero, the current default
109 * read buffer size is returned without modifying it.
110 * @return The previous default read buffer size.
111 */
112int32_t SDDS_SetDefaultReadBufferSize(int32_t newSize) {
113 int32_t previous;
114 if (newSize <= 0)
115 return SDDS_GetLockedDefaultReadBufferSize();
116 mdb_thread_lock(&defaultReadBufferSizeLock);
117 previous = defaultReadBufferSize;
118 defaultReadBufferSize = newSize;
119 mdb_thread_unlock(&defaultReadBufferSizeLock);
120 return previous;
121}
122
123/**
124 * @brief Set the default write buffer size for SDDS.
125 *
126 * This function updates the default buffer size used for writing SDDS binary data.
127 *
128 * @param newSize The new buffer size to set. Must be greater than zero.
129 * If newSize is less than or equal to zero, the current default
130 * write buffer size is returned without modifying it.
131 * @return The previous default write buffer size.
132 */
133int32_t SDDS_SetDefaultWriteBufferSize(int32_t newSize) {
134 int32_t previous;
135 if (newSize <= 0)
136 return SDDS_GetLockedDefaultWriteBufferSize();
137 mdb_thread_lock(&defaultWriteBufferSizeLock);
138 previous = defaultWriteBufferSize;
139 defaultWriteBufferSize = newSize;
140 mdb_thread_unlock(&defaultWriteBufferSizeLock);
141 return previous;
142}
143
144/**
145 * @brief Set the default title buffer size for SDDS.
146 *
147 * This function updates the default buffer size used for storing SDDS titles.
148 *
149 * @param newSize The new buffer size to set. Must be greater than zero.
150 * If newSize is less than or equal to zero, the current default
151 * title buffer size is returned without modifying it.
152 * @return The previous default title buffer size.
153 */
154int32_t SDDS_SetDefaultTitleBufferSize(int32_t newSize) {
155 int32_t previous;
156 if (newSize <= 0)
157 return SDDS_GetLockedDefaultTitleBufferSize();
158 mdb_thread_lock(&defaultTitleBufferSizeLock);
159 previous = defaultTitleBufferSize;
160 defaultTitleBufferSize = newSize;
161 mdb_thread_unlock(&defaultTitleBufferSizeLock);
162 return previous;
163}
164
165/**
166 * @brief Check the number of truncated strings.
167 *
168 * This function returns the number of strings that have been truncated
169 * due to exceeding the default string length.
170 *
171 * @return The number of truncated strings.
172 */
174 int32_t count;
175
176 mdb_thread_lock(&number_of_string_truncated_lock);
177 count = number_of_string_truncated;
178 mdb_thread_unlock(&number_of_string_truncated_lock);
179 return count;
180}
181
182/**
183 * @brief Increment the truncated strings counter.
184 *
185 * This function increments the count of strings that have been truncated.
186 */
188 mdb_thread_lock(&number_of_string_truncated_lock);
189 number_of_string_truncated++;
190 mdb_thread_unlock(&number_of_string_truncated_lock);
191}
192
193/**
194 * @brief Set the default string length for SDDS.
195 *
196 * This function updates the default maximum length for string columns in SDDS.
197 *
198 * @param newValue The new string length to set. Must be non-negative.
199 * If newValue is negative, the current default string length
200 * is returned without modifying it.
201 * @return The previous default string length.
202 */
203int32_t SDDS_SetDefaultStringLength(int32_t newValue) {
204 int32_t previous;
205 if (newValue < 0)
206 return SDDS_GetLockedDefaultStringLength();
207 mdb_thread_lock(&defaultStringLengthLock);
208 previous = defaultStringLength;
209 defaultStringLength = newValue;
210 mdb_thread_unlock(&defaultStringLengthLock);
211 return previous;
212}
213
214/**
215 * @brief Write an SDDS binary page using MPI.
216 *
217 * This function writes an SDDS dataset as a binary page using MPI.
218 * If MPI_DEBUG is enabled, it logs debugging information.
219 *
220 * @param SDDS_dataset Pointer to the SDDS_DATASET structure to write.
221 * @return 1 on success, 0 on failure.
222 */
224#if MPI_DEBUG
225 logDebug("SDDS_MPI_WriteBinaryPage", SDDS_dataset);
226#endif
227 /* usleep(1000000); Doesn't solve problem of corrupted data */
228 return SDDS_MPI_WriteContinuousBinaryPage(SDDS_dataset);
229}
230
231/**
232 * @brief Write a binary string to an SDDS dataset using MPI.
233 *
234 * This function writes a string to the SDDS dataset in binary format using MPI.
235 * If the provided string is NULL, a dummy empty string is written instead.
236 *
237 * @param SDDS_dataset Pointer to the SDDS_DATASET structure.
238 * @param string The string to write. If NULL, an empty string is written.
239 * @return 1 on success, 0 on failure.
240 */
241int32_t SDDS_MPI_WriteBinaryString(SDDS_DATASET *SDDS_dataset, char *string) {
242 int32_t length;
243
244#if MPI_DEBUG
245 logDebug("SDDS_MPI_WriteBinaryString", SDDS_dataset);
246#endif
247
248 if (!string)
249 string = "";
250
251 length = strlen(string);
252 if (!SDDS_MPI_BufferedWrite(&length, sizeof(length), SDDS_dataset))
253 return 0;
254 if (length && !SDDS_MPI_BufferedWrite(string, sizeof(*string) * length, SDDS_dataset))
255 return 0;
256 return 1;
257}
258
259/**
260 * @brief Write a non-native binary string to an SDDS dataset using MPI.
261 *
262 * This function writes a string to the SDDS dataset in non-native binary format
263 * using MPI, handling byte swapping as necessary. If the provided string is NULL,
264 * a dummy empty string is written instead.
265 *
266 * @param SDDS_dataset Pointer to the SDDS_DATASET structure.
267 * @param string The string to write. If NULL, an empty string is written.
268 * @return 1 on success, 0 on failure.
269 */
270int32_t SDDS_MPI_WriteNonNativeBinaryString(SDDS_DATASET *SDDS_dataset, char *string) {
271 int32_t length;
272
273#if MPI_DEBUG
274 logDebug("SDDS_MPI_WriteNonNativeBinaryString", SDDS_dataset);
275#endif
276
277 if (!string)
278 string = "";
279
280 length = strlen(string);
281 SDDS_SwapLong(&length);
282 if (!SDDS_MPI_BufferedWrite(&length, sizeof(length), SDDS_dataset))
283 return 0;
284 SDDS_SwapLong(&length);
285 if (length && !SDDS_MPI_BufferedWrite(string, sizeof(*string) * length, SDDS_dataset))
286 return 0;
287 return 1;
288}
289
290/**
291 * @brief Write binary parameters of an SDDS dataset using MPI.
292 *
293 * This function writes all non-fixed parameters of the SDDS dataset in binary format
294 * using MPI. String parameters are written using SDDS_MPI_WriteBinaryString,
295 * and other types are written directly to the buffer.
296 *
297 * Only the master processor should call this function to write SDDS headers,
298 * parameters, and arrays.
299 *
300 * @param SDDS_dataset Pointer to the SDDS_DATASET structure.
301 * @return 1 on success, 0 on failure.
302 */
304 SDDS_LAYOUT *layout;
305 int32_t i;
306
307#if MPI_DEBUG
308 logDebug("SDDS_MPI_WriteBinaryParameters", SDDS_dataset);
309#endif
310
311 /*should only master processors write SDDS hearder,parameters and arrays */
312 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_MPI_WriteBinaryParameters"))
313 return (0);
314 layout = &SDDS_dataset->layout;
315 for (i = 0; i < layout->n_parameters; i++) {
316 if (layout->parameter_definition[i].fixed_value)
317 continue;
318 if (layout->parameter_definition[i].type == SDDS_STRING) {
319 if (!SDDS_MPI_WriteBinaryString(SDDS_dataset, *(char **)SDDS_dataset->parameter[i]))
320 return 0;
321 } else {
322 if (!SDDS_MPI_BufferedWrite(SDDS_dataset->parameter[i], SDDS_type_size[layout->parameter_definition[i].type - 1], SDDS_dataset))
323 return 0;
324 }
325 }
326 return (1);
327}
328
329/**
330 * @brief Write non-native binary parameters of an SDDS dataset using MPI.
331 *
332 * This function writes all non-fixed parameters of the SDDS dataset in non-native
333 * binary format using MPI, handling byte swapping as necessary.
334 * String parameters are written using SDDS_MPI_WriteNonNativeBinaryString,
335 * and other types are written directly to the buffer.
336 *
337 * Only the master processor should call this function to write SDDS headers,
338 * parameters, and arrays.
339 *
340 * @param SDDS_dataset Pointer to the SDDS_DATASET structure.
341 * @return 1 on success, 0 on failure.
342 */
344 SDDS_LAYOUT *layout;
345 int32_t i;
346
347#if MPI_DEBUG
348 logDebug("SDDS_MPI_WriteNonNativeBinaryParameters", SDDS_dataset);
349#endif
350
351 /*should only master processors write SDDS hearder,parameters and arrays */
352 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_MPI_WriteBinaryParameters"))
353 return (0);
354 layout = &SDDS_dataset->layout;
355 SDDS_SwapEndsParameterData(SDDS_dataset);
356 for (i = 0; i < layout->n_parameters; i++) {
357 if (layout->parameter_definition[i].fixed_value)
358 continue;
359 if (layout->parameter_definition[i].type == SDDS_STRING) {
360 if (!SDDS_MPI_WriteNonNativeBinaryString(SDDS_dataset, *(char **)SDDS_dataset->parameter[i])) {
361 SDDS_SwapEndsParameterData(SDDS_dataset);
362 return 0;
363 }
364 } else {
365 if (!SDDS_MPI_BufferedWrite(SDDS_dataset->parameter[i], SDDS_type_size[layout->parameter_definition[i].type - 1], SDDS_dataset)) {
366 SDDS_SwapEndsParameterData(SDDS_dataset);
367 return 0;
368 }
369 }
370 }
371 SDDS_SwapEndsParameterData(SDDS_dataset);
372 return (1);
373}
374
375/**
376 * @brief Write binary arrays of an SDDS dataset using MPI.
377 *
378 * This function writes all arrays of the SDDS dataset in binary format using MPI.
379 * It handles different types of arrays, including strings and fixed-size data types.
380 *
381 * Only the master processor should call this function to write SDDS headers,
382 * parameters, and arrays.
383 *
384 * @param SDDS_dataset Pointer to the SDDS_DATASET structure.
385 * @return 1 on success, 0 on failure.
386 */
388 int32_t i, j, zero = 0, writeSize = 0;
389 SDDS_LAYOUT *layout;
390
391 /*only the master processor write SDDS header, parameters and arrays */
392 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_MPI_WriteBinaryArray"))
393 return (0);
394 layout = &SDDS_dataset->layout;
395 for (i = 0; i < layout->n_arrays; i++) {
396 if (!SDDS_dataset->array[i].dimension) {
397 for (j = 0; j < layout->array_definition[i].dimensions; j++) {
398 if (!SDDS_MPI_BufferedWrite(&zero, sizeof(zero), SDDS_dataset)) {
399 SDDS_SetError("Unable to write null array--failure writing dimensions (SDDS_MPI_WriteBinaryArrays)");
400 return 0;
401 }
402 }
403 continue;
404 }
405 writeSize = sizeof(*(SDDS_dataset->array)[i].dimension) * layout->array_definition[i].dimensions;
406 if (!SDDS_MPI_BufferedWrite(SDDS_dataset->array[i].dimension, writeSize, SDDS_dataset)) {
407 SDDS_SetError("Unable to write arrays--failure writing dimensions (SDDS_MPI_WriteBinaryArrays)");
408 return (0);
409 }
410 if (layout->array_definition[i].type == SDDS_STRING) {
411 for (j = 0; j < SDDS_dataset->array[i].elements; j++) {
412 if (!SDDS_MPI_WriteBinaryString(SDDS_dataset, ((char **)SDDS_dataset->array[i].data)[j])) {
413 SDDS_SetError("Unable to write arrays--failure writing string (SDDS_WriteBinaryArrays)");
414 return (0);
415 }
416 }
417 } else {
418 writeSize = SDDS_type_size[layout->array_definition[i].type - 1] * SDDS_dataset->array[i].elements;
419 if (!SDDS_MPI_BufferedWrite(SDDS_dataset->array[i].data, writeSize, SDDS_dataset)) {
420 SDDS_SetError("Unable to write arrays--failure writing values (SDDS_MPI_WriteBinaryArrays)");
421 return (0);
422 }
423 }
424 }
425 return (1);
426}
427
428/**
429 * @brief Write non-native binary arrays of an SDDS dataset using MPI.
430 *
431 * This function writes all arrays of the SDDS dataset in non-native binary format
432 * using MPI, handling byte swapping as necessary. It handles different types of
433 * arrays, including strings and fixed-size data types.
434 *
435 * Only the master processor should call this function to write SDDS headers,
436 * parameters, and arrays.
437 *
438 * @param SDDS_dataset Pointer to the SDDS_DATASET structure.
439 * @return 1 on success, 0 on failure.
440 */
442 int32_t i, j, zero = 0, writeSize = 0;
443 SDDS_LAYOUT *layout;
444
445 /*only the master processor write SDDS header, parameters and arrays */
446
447 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_MPI_WriteBinaryArray"))
448 return (0);
449 SDDS_SwapEndsArrayData(SDDS_dataset);
450 layout = &SDDS_dataset->layout;
451 for (i = 0; i < layout->n_arrays; i++) {
452 if (!SDDS_dataset->array[i].dimension) {
453 for (j = 0; j < layout->array_definition[i].dimensions; j++) {
454 if (!SDDS_MPI_BufferedWrite(&zero, sizeof(zero), SDDS_dataset)) {
455 SDDS_SetError("Unable to write null array--failure writing dimensions (SDDS_MPI_WriteBinaryArrays)");
456 SDDS_SwapEndsArrayData(SDDS_dataset);
457 return 0;
458 }
459 }
460 continue;
461 }
462 writeSize = sizeof(*(SDDS_dataset->array)[i].dimension) * layout->array_definition[i].dimensions;
463 if (!SDDS_MPI_BufferedWrite(SDDS_dataset->array[i].dimension, writeSize, SDDS_dataset)) {
464 SDDS_SetError("Unable to write arrays--failure writing dimensions (SDDS_MPI_WriteBinaryArrays)");
465 SDDS_SwapEndsArrayData(SDDS_dataset);
466 return (0);
467 }
468 if (layout->array_definition[i].type == SDDS_STRING) {
469 for (j = 0; j < SDDS_dataset->array[i].elements; j++) {
470 if (!SDDS_MPI_WriteNonNativeBinaryString(SDDS_dataset, ((char **)SDDS_dataset->array[i].data)[j])) {
471 SDDS_SetError("Unable to write arrays--failure writing string (SDDS_WriteBinaryArrays)");
472 SDDS_SwapEndsArrayData(SDDS_dataset);
473 return (0);
474 }
475 }
476 } else {
477 writeSize = SDDS_type_size[layout->array_definition[i].type - 1] * SDDS_dataset->array[i].elements;
478 if (!SDDS_MPI_BufferedWrite(SDDS_dataset->array[i].data, writeSize, SDDS_dataset)) {
479 SDDS_SetError("Unable to write arrays--failure writing values (SDDS_MPI_WriteBinaryArrays)");
480 SDDS_SwapEndsArrayData(SDDS_dataset);
481 return (0);
482 }
483 }
484 }
485 SDDS_SwapEndsArrayData(SDDS_dataset);
486 return (1);
487}
488
489/**
490 * @brief Set the write kludge usleep duration.
491 *
492 * This function sets the duration (in microseconds) for the write kludge
493 * sleep operation. This is used to fix write issues in certain test cases
494 * by introducing a delay after writing a binary row.
495 *
496 * @param value The number of microseconds to sleep after writing a row.
497 */
499 mdb_thread_lock(&SDDS_MPI_write_kludge_usleep_lock);
500 SDDS_MPI_write_kludge_usleep = value;
501 mdb_thread_unlock(&SDDS_MPI_write_kludge_usleep_lock);
502}
503
504/**
505 * @brief Set the file synchronization flag.
506 *
507 * This function enables or disables forced file synchronization after writing
508 * binary rows. This can help prevent data corruption by ensuring data is flushed
509 * to the file system.
510 *
511 * @param value A short integer where non-zero enables file synchronization,
512 * and zero disables it.
513 */
514void SDDS_MPI_SetFileSync(short value) {
515 mdb_thread_lock(&SDDS_MPI_force_file_sync_lock);
516 SDDS_MPI_force_file_sync = value;
517 mdb_thread_unlock(&SDDS_MPI_force_file_sync_lock);
518}
519
520/**
521 * @brief Write a binary row to an SDDS dataset using MPI.
522 *
523 * This function writes a specific row of data from the SDDS dataset in binary
524 * format using MPI. It handles different column types, including strings with
525 * truncation based on the default string length. Optional write kludge delays
526 * and file synchronization can be applied based on configuration.
527 *
528 * @param SDDS_dataset Pointer to the SDDS_DATASET structure.
529 * @param row The row index to write.
530 * @return 1 on success, 0 on failure.
531 */
532int32_t SDDS_MPI_WriteBinaryRow(SDDS_DATASET *SDDS_dataset, int64_t row) {
533 int32_t size, type;
534 int64_t i;
535 SDDS_LAYOUT *layout;
536 /*char buff[defaultStringLength+1], format[256]; */
537 char *buff;
538 char format[256];
539 int32_t currentDefaultStringLength;
540 long writeKludgeUsleep;
541
542#if MPI_DEBUG
543 logDebug("SDDS_MPI_WriteBinaryRow", SDDS_dataset);
544#endif
545
546 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_WriteBinaryRow"))
547 return (0);
548
549 layout = &SDDS_dataset->layout;
550 currentDefaultStringLength = SDDS_GetLockedDefaultStringLength();
551
552 if (currentDefaultStringLength < 0 || currentDefaultStringLength >= INT32_MAX) {
553 SDDS_SetError("Default string length is too large in SDDS_MPI_WriteBinaryRow!");
554 return 0;
555 }
556 if (snprintf(format, sizeof(format), "%%-%" PRId32 "s", currentDefaultStringLength) >= (int)sizeof(format)) {
557 SDDS_SetError("Default string length is too large in SDDS_MPI_WriteBinaryRow!");
558 return 0;
559 }
560 if (!(buff = malloc(sizeof(*buff) * ((size_t)currentDefaultStringLength + 1)))) {
561 SDDS_SetError("Can not allocate memory in SDDS_MPI_WriteBinaryRow!");
562 return 0;
563 }
564 buff[currentDefaultStringLength] = 0;
565 for (i = 0; i < layout->n_columns; i++) {
566 type = layout->column_definition[i].type;
567 size = SDDS_type_size[type - 1];
568
569 if (type == SDDS_STRING) {
570 if (strlen(*((char **)SDDS_dataset->data[i] + row)) <= currentDefaultStringLength)
571 sprintf(buff, format, *((char **)SDDS_dataset->data[i] + row));
572 else {
573 strncpy(buff, *((char **)SDDS_dataset->data[i] + row), currentDefaultStringLength);
575 }
576 if (!SDDS_MPI_WriteBinaryString(SDDS_dataset, buff)) {
577 free(buff);
578 return 0;
579 }
580 } else {
581 size = SDDS_type_size[type - 1];
582 if (!SDDS_MPI_BufferedWrite((char *)SDDS_dataset->data[i] + row * size, size, SDDS_dataset)) {
583 free(buff);
584 return 0;
585 }
586 }
587 }
588 free(buff);
589 writeKludgeUsleep = SDDS_MPI_GetLockedWriteKludgeUsleep();
590 if (writeKludgeUsleep)
591 usleepSystemIndependent(writeKludgeUsleep); /* This fixes write issue in test case. No data corruption observed. */
592 if (SDDS_MPI_GetLockedForceFileSync())
593 MPI_File_sync(SDDS_dataset->MPI_dataset->MPI_file); /* This also seems to fix it. */
594 return (1);
595}
596
597/**
598 * @brief Write a non-native binary row to an SDDS dataset using MPI.
599 *
600 * This function writes a specific row of data from the SDDS dataset in non-native
601 * binary format using MPI, handling byte swapping as necessary. It manages different
602 * column types, including strings with truncation based on the default string length.
603 * Optional write kludge delays and file synchronization can be applied based on configuration.
604 *
605 * @param SDDS_dataset Pointer to the SDDS_DATASET structure.
606 * @param row The row index to write.
607 * @return 1 on success, 0 on failure.
608 */
609int32_t SDDS_MPI_WriteNonNativeBinaryRow(SDDS_DATASET *SDDS_dataset, int64_t row) {
610 int32_t size, type;
611 int64_t i;
612 SDDS_LAYOUT *layout;
613 /*char buff[defaultStringLength+1], format[256]; */
614 char *buff;
615 char format[256];
616 int32_t currentDefaultStringLength;
617 long writeKludgeUsleep;
618#if MPI_DEBUG
619 logDebug("SDDS_MPI_WriteNonNativeBinaryRow", SDDS_dataset);
620#endif
621
622 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_WriteBinaryRow"))
623 return (0);
624
625 layout = &SDDS_dataset->layout;
626 currentDefaultStringLength = SDDS_GetLockedDefaultStringLength();
627
628 if (currentDefaultStringLength < 0 || currentDefaultStringLength >= INT32_MAX) {
629 SDDS_SetError("Default string length is too large in SDDS_MPI_WriteNonNativeBinaryRow!");
630 return 0;
631 }
632 if (snprintf(format, sizeof(format), "%%-%" PRId32 "s", currentDefaultStringLength) >= (int)sizeof(format)) {
633 SDDS_SetError("Default string length is too large in SDDS_MPI_WriteNonNativeBinaryRow!");
634 return 0;
635 }
636 if (!(buff = malloc(sizeof(*buff) * ((size_t)currentDefaultStringLength + 1)))) {
637 SDDS_SetError("Can not allocate memory in SDDS_MPI_WriteNonNativeBinaryRow!");
638 return 0;
639 }
640 buff[currentDefaultStringLength] = 0;
641 for (i = 0; i < layout->n_columns; i++) {
642 type = layout->column_definition[i].type;
643 size = SDDS_type_size[type - 1];
644
645 if (type == SDDS_STRING) {
646 if (strlen(*((char **)SDDS_dataset->data[i] + row)) <= currentDefaultStringLength)
647 sprintf(buff, format, *((char **)SDDS_dataset->data[i] + row));
648 else {
649 strncpy(buff, *((char **)SDDS_dataset->data[i] + row), currentDefaultStringLength);
651 }
652 if (!SDDS_MPI_WriteNonNativeBinaryString(SDDS_dataset, buff)) {
653 free(buff);
654 return 0;
655 }
656 } else {
657 size = SDDS_type_size[type - 1];
658 if (!SDDS_MPI_BufferedWrite((char *)SDDS_dataset->data[i] + row * size, size, SDDS_dataset)) {
659 free(buff);
660 return 0;
661 }
662 }
663 }
664 free(buff);
665 writeKludgeUsleep = SDDS_MPI_GetLockedWriteKludgeUsleep();
666 if (writeKludgeUsleep)
667 usleepSystemIndependent(writeKludgeUsleep); /* This fixes write issue in test case. No data corruption observed. */
668 if (SDDS_MPI_GetLockedForceFileSync())
669 MPI_File_sync(SDDS_dataset->MPI_dataset->MPI_file); /* This also seems to fix it. */
670 return (1);
671}
672
673/**
674 * @brief Get the total size of all columns in an SDDS dataset.
675 *
676 * This function calculates the total size in bytes required to store all columns
677 * of the SDDS dataset in binary format. For string columns, it includes space
678 * for the string length and the fixed maximum string length.
679 *
680 * @param SDDS_dataset Pointer to the SDDS_DATASET structure.
681 * @return The total size of all columns in bytes.
682 */
683MPI_Offset SDDS_MPI_Get_Column_Size(SDDS_DATASET *SDDS_dataset) {
684 int64_t i;
685 MPI_Offset column_offset = 0;
686 SDDS_LAYOUT *layout;
687 int32_t currentDefaultStringLength;
688
689 layout = &SDDS_dataset->layout;
690 currentDefaultStringLength = SDDS_GetLockedDefaultStringLength();
691 for (i = 0; i < layout->n_columns; i++) {
692 if (layout->column_definition[i].type == SDDS_STRING)
693 /* for string type column, the fixed column size defined by user use SDDS_SetDefaultStringLength(value),
694 and the length of string is written before the string */
695 column_offset += sizeof(int32_t) + currentDefaultStringLength * sizeof(char);
696 else
697 column_offset += SDDS_type_size[layout->column_definition[i].type - 1];
698 }
699 return column_offset;
700}
701
702/**
703 * @brief Buffered write to an SDDS dataset using MPI.
704 *
705 * This function writes data to the SDDS dataset using a buffer. If the buffer has
706 * sufficient space, the data is copied into the buffer. Otherwise, the buffer is
707 * flushed to the file, and the new data is either written directly or stored in the buffer.
708 *
709 * @param target Pointer to the data to write.
710 * @param targetSize The size of the data to write, in bytes.
711 * @param SDDS_dataset Pointer to the SDDS_DATASET structure.
712 * @return 1 on success, 0 on failure.
713 */
714int32_t SDDS_MPI_BufferedWrite(void *target, int64_t targetSize, SDDS_DATASET *SDDS_dataset) {
715 SDDS_FILEBUFFER *fBuffer;
716 MPI_DATASET *MPI_dataset;
717 int32_t mpi_code;
718
719#if MPI_DEBUG
720 logDebug("SDDS_MPI_BufferedWrite", SDDS_dataset);
721#endif
722 MPI_dataset = SDDS_dataset->MPI_dataset;
723 fBuffer = &(SDDS_dataset->fBuffer);
724
725 if (!fBuffer->bufferSize) {
726 if ((mpi_code = MPI_File_write(MPI_dataset->MPI_file, target, targetSize, MPI_BYTE, MPI_STATUS_IGNORE)) != MPI_SUCCESS) {
727 SDDS_MPI_GOTO_ERROR(stderr, "SDDS_MPI_WriteBufferedWrite(MPI_File_write_at failed)", mpi_code, 0);
728 return 0;
729 }
730 return 1;
731 }
732 if ((fBuffer->bytesLeft -= targetSize) >= 0) {
733 memcpy((char *)fBuffer->data, (char *)target, targetSize);
734 fBuffer->data += targetSize;
735#ifdef DEBUG
736 fprintf(stderr, "SDDS_MPI_BufferedWrite of %" PRId64 " bytes done in-memory, %" PRId64 " bytes left\n", targetSize, fBuffer->bytesLeft);
737#endif
738 return 1;
739 } else {
740 int64_t lastLeft;
741 /* add back what was subtracted in test above.
742 * lastLeft is the number of bytes left in the buffer before doing anything
743 * and also the number of bytes from the users data that get copied into the buffer.
744 */
745 lastLeft = (fBuffer->bytesLeft += targetSize);
746 /* copy part of the data into the buffer and write the buffer out */
747 memcpy((char *)fBuffer->data, (char *)target, (size_t)fBuffer->bytesLeft);
748 if ((mpi_code = MPI_File_write(MPI_dataset->MPI_file, fBuffer->buffer, (int)(fBuffer->bufferSize), MPI_BYTE, MPI_STATUS_IGNORE)) != MPI_SUCCESS) {
749 SDDS_MPI_GOTO_ERROR(stderr, "SDDS_MPI_WriteBufferedWrite(MPI_File_write_at failed)", mpi_code, 0);
750 return 0;
751 }
752
753 /* reset the data pointer and the bytesLeft value.
754 * also, determine if the remaining data is too large for the buffer.
755 * if so, just write it out.
756 */
757 fBuffer->data = fBuffer->buffer;
758 if ((targetSize -= lastLeft) > (fBuffer->bytesLeft = fBuffer->bufferSize)) {
759 if ((mpi_code = MPI_File_write_at(MPI_dataset->MPI_file, (MPI_Offset)(MPI_dataset->file_offset), (char *)target + lastLeft, targetSize, MPI_BYTE, MPI_STATUS_IGNORE)) != MPI_SUCCESS) {
760 SDDS_MPI_GOTO_ERROR(stderr, "SDDS_MPI_WriteBufferedWrite(MPI_File_write_at failed)", mpi_code, 0);
761 return 0;
762 }
763 return 1;
764 }
765 /* copy remaining data into the buffer.
766 * could do this with a recursive call, but this is more efficient.
767 */
768 memcpy((char *)fBuffer->data, (char *)target + lastLeft, targetSize);
769 fBuffer->data += targetSize;
770 fBuffer->bytesLeft -= targetSize;
771 return 1;
772 }
773}
774
775/**
776 * @brief Buffered write all to an SDDS dataset using MPI.
777 *
778 * This function writes all data to the SDDS dataset using a buffer, ensuring that
779 * all data is written even if the buffer needs to be flushed multiple times.
780 *
781 * @param target Pointer to the data to write.
782 * @param targetSize The size of the data to write, in bytes.
783 * @param SDDS_dataset Pointer to the SDDS_DATASET structure.
784 * @return 1 on success, 0 on failure.
785 */
786int32_t SDDS_MPI_BufferedWriteAll(void *target, int64_t targetSize, SDDS_DATASET *SDDS_dataset) {
787 SDDS_FILEBUFFER *fBuffer;
788 MPI_DATASET *MPI_dataset;
789 int32_t mpi_code;
790
791#if MPI_DEBUG
792 logDebug("SDDS_MPI_BufferedWriteAll", SDDS_dataset);
793#endif
794 MPI_dataset = SDDS_dataset->MPI_dataset;
795 fBuffer = &(SDDS_dataset->fBuffer);
796
797 if (!fBuffer->bufferSize) {
798 if ((mpi_code = MPI_File_write_all(MPI_dataset->MPI_file, target, targetSize, MPI_BYTE, MPI_STATUS_IGNORE)) != MPI_SUCCESS) {
799 SDDS_MPI_GOTO_ERROR(stderr, "SDDS_MPI_WriteBufferedWrite(MPI_File_write_at failed)", mpi_code, 0);
800 return 0;
801 }
802 return 1;
803 }
804 if ((fBuffer->bytesLeft -= targetSize) >= 0) {
805 memcpy((char *)fBuffer->data, (char *)target, targetSize);
806 fBuffer->data += targetSize;
807#ifdef DEBUG
808 fprintf(stderr, "SDDS_MPI_BufferedWrite of %" PRId64 " bytes done in-memory, %" PRId64 " bytes left\n", targetSize, fBuffer->bytesLeft);
809#endif
810 return 1;
811 } else {
812 int64_t lastLeft;
813 /* add back what was subtracted in test above.
814 * lastLeft is the number of bytes left in the buffer before doing anything
815 * and also the number of bytes from the users data that get copied into the buffer.
816 */
817 lastLeft = (fBuffer->bytesLeft += targetSize);
818 /* copy part of the data into the buffer and write the buffer out */
819 memcpy((char *)fBuffer->data, (char *)target, (size_t)fBuffer->bytesLeft);
820 if ((mpi_code = MPI_File_write_all(MPI_dataset->MPI_file, fBuffer->buffer, (int)(fBuffer->bufferSize), MPI_BYTE, MPI_STATUS_IGNORE)) != MPI_SUCCESS) {
821 SDDS_MPI_GOTO_ERROR(stderr, "SDDS_MPI_WriteBufferedWrite(MPI_File_write_at failed)", mpi_code, 0);
822 return 0;
823 }
824
825 /* reset the data pointer and the bytesLeft value.
826 * also, determine if the remaining data is too large for the buffer.
827 * if so, just write it out.
828 */
829 fBuffer->data = fBuffer->buffer;
830 if ((targetSize -= lastLeft) > (fBuffer->bytesLeft = fBuffer->bufferSize)) {
831 if ((mpi_code = MPI_File_write_all(MPI_dataset->MPI_file, (char *)target + lastLeft, targetSize, MPI_BYTE, MPI_STATUS_IGNORE)) != MPI_SUCCESS) {
832 SDDS_MPI_GOTO_ERROR(stderr, "SDDS_MPI_WriteBufferedWrite(MPI_File_write_at failed)", mpi_code, 0);
833 return 0;
834 }
835 return 1;
836 }
837 /* copy remaining data into the buffer.
838 * could do this with a recursive call, but this is more efficient.
839 */
840 memcpy((char *)fBuffer->data, (char *)target + lastLeft, targetSize);
841 fBuffer->data += targetSize;
842 fBuffer->bytesLeft -= targetSize;
843 return 1;
844 }
845}
846
847/**
848 * @brief Flush the buffer by writing any remaining data to the MPI file.
849 *
850 * This function ensures that any data remaining in the buffer is written to the MPI file.
851 * It handles error checking and resets the buffer pointers upon successful write.
852 *
853 * @param SDDS_dataset Pointer to the SDDS_DATASET structure.
854 * @return
855 * - `1` on successful flush.
856 * - `0` on failure.
857 */
858int32_t SDDS_MPI_FlushBuffer(SDDS_DATASET *SDDS_dataset) {
859 SDDS_FILEBUFFER *fBuffer;
860 MPI_DATASET *MPI_dataset;
861 int64_t writeBytes;
862 int32_t mpi_code;
863
864#if MPI_DEBUG
865 logDebug("SDDS_MPI_FlushBuffer", SDDS_dataset);
866#endif
867
868 MPI_dataset = SDDS_dataset->MPI_dataset;
869 fBuffer = &(SDDS_dataset->fBuffer);
870
871 if (!fBuffer->bufferSize)
872 return 1;
873
874 if ((writeBytes = fBuffer->bufferSize - fBuffer->bytesLeft)) {
875 if (writeBytes < 0) {
876 SDDS_SetError("Unable to flush buffer: negative byte count (SDDS_FlushBuffer).");
877 return 0;
878 }
879#ifdef DEBUG
880 fprintf(stderr, "Writing %" PRId64 " bytes to disk\n", writeBytes);
881#endif
882 if ((mpi_code = MPI_File_write(MPI_dataset->MPI_file, fBuffer->buffer, writeBytes, MPI_BYTE, MPI_STATUS_IGNORE)) != MPI_SUCCESS) {
883 SDDS_MPI_GOTO_ERROR(stderr, "SDDS_MPI_FlushBuffer(MPI_File_write_at failed)", mpi_code, 0);
884 return 0;
885 }
886 fBuffer->bytesLeft = fBuffer->bufferSize;
887 fBuffer->data = fBuffer->buffer;
888 }
889 return 1;
890}
891
892/**
893 * @brief Count the number of rows marked as "of interest" within a specified range.
894 *
895 * This function iterates through the rows of the SDDS dataset from `start_row` to `end_row`
896 * and counts how many rows have their `row_flag` set to indicate they are of interest.
897 *
898 * @param SDDS_dataset Pointer to the SDDS_DATASET structure.
899 * @param start_row The starting row index (inclusive) to begin counting.
900 * @param end_row The ending row index (exclusive) to stop counting.
901 * @return The total number of rows marked as of interest within the specified range.
902 */
903int64_t SDDS_MPI_CountRowsOfInterest(SDDS_DATASET *SDDS_dataset, int64_t start_row, int64_t end_row) {
904 int64_t i, rows = 0;
905 for (i = start_row; i < end_row; i++) {
906 if (i > SDDS_dataset->n_rows - 1)
907 break;
908 if (SDDS_dataset->row_flag[i])
909 rows++;
910 }
911 return rows;
912}
913
914/**
915 * @brief Get the total number of rows across all MPI processes.
916 *
917 * This function uses MPI_Reduce to sum the number of rows (`n_rows`) from all processes
918 * and returns the total number of rows to the root process (process 0).
919 *
920 * @param SDDS_dataset Pointer to the SDDS_DATASET structure.
921 * @return The total number of rows across all MPI processes. Only valid on the root process.
922 */
923int64_t SDDS_MPI_GetTotalRows(SDDS_DATASET *SDDS_dataset) {
924 int64_t total_rows;
925 MPI_Reduce(&(SDDS_dataset->n_rows), &total_rows, 1, MPI_INT64_T, MPI_SUM, 0, SDDS_dataset->MPI_dataset->comm);
926 return total_rows;
927}
928
929/**
930 * @brief Write a non-native binary page of the SDDS dataset using MPI.
931 *
932 * This function handles the writing of an entire SDDS dataset page in non-native binary format.
933 * It manages buffer allocation, handles byte swapping for non-native formats, and ensures
934 * that all parameters and arrays are correctly written. It also coordinates writing across
935 * multiple MPI processes.
936 *
937 * @param SDDS_dataset Pointer to the SDDS_DATASET structure.
938 * @return
939 * - `1` on successful write.
940 * - `0` on failure.
941 */
943 int64_t row, prev_rows, i, total_rows, fixed_rows, rows;
944 int mpi_code, type = 0;
945 MPI_Offset column_offset, rowcount_offset, offset;
946 int64_t *n_rows = NULL;
947 MPI_Status status;
948 int32_t min32 = INT32_MIN;
949
950 MPI_DATASET *MPI_dataset = NULL;
951 SDDS_FILEBUFFER *fBuffer;
952
953#if MPI_DEBUG
954 logDebug("SDDS_MPI_WriteNonNativeBinaryPage", SDDS_dataset);
955#endif
956
957 MPI_dataset = SDDS_dataset->MPI_dataset;
958
959#if MPI_DEBUG
960
961#endif
962
963 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_MPI_WriteNonNativeBinaryPage"))
964 return (0);
965
966 fBuffer = &SDDS_dataset->fBuffer;
967 if (SDDS_dataset->layout.data_mode.column_major)
968 /*write by column ignores the row flag and buffer is not needed for writing data by column */
969 rows = SDDS_dataset->n_rows;
970 else {
971 rows = SDDS_CountRowsOfInterest(SDDS_dataset);
972 if (!fBuffer->buffer) {
973 fBuffer->bufferSize = SDDS_GetLockedDefaultWriteBufferSize();
974 if (!(fBuffer->buffer = fBuffer->data = SDDS_Malloc(sizeof(char) * (fBuffer->bufferSize + 1)))) {
975 SDDS_SetError("Unable to do buffered read--allocation failure (SDDS_WriteNonNativeBinaryPage)");
976 return 0;
977 }
978 fBuffer->bytesLeft = fBuffer->bufferSize;
979 fBuffer->data[0] = 0;
980 }
981 }
982 if (MPI_dataset->n_page >= 1)
983 MPI_File_set_view(MPI_dataset->MPI_file, MPI_dataset->file_offset, MPI_BYTE, MPI_BYTE, "native", MPI_INFO_NULL);
984 rowcount_offset = MPI_dataset->file_offset + SDDS_MPI_GetTitleOffset(SDDS_dataset); /* the offset before writing rows */
985 /*get total number of rows writing */
986 column_offset = MPI_dataset->column_offset;
987 if (!(n_rows = calloc(sizeof(*n_rows), MPI_dataset->n_processors))) {
988 SDDS_SetError("Memory allocation failed!");
989 return 0;
990 }
991 MPI_Allgather(&rows, 1, MPI_INT64_T, n_rows, 1, MPI_INT64_T, MPI_dataset->comm);
992 prev_rows = 0;
993 for (i = 0; i < MPI_dataset->myid; i++)
994 prev_rows += n_rows[i];
995 total_rows = 0;
996 for (i = 0; i < MPI_dataset->n_processors; i++)
997 total_rows += n_rows[i];
998 if (MPI_dataset->myid == 0) {
999 fixed_rows = total_rows;
1000 if (!fBuffer->buffer) {
1001 fBuffer->bufferSize = SDDS_GetLockedDefaultWriteBufferSize();
1002 if (!(fBuffer->buffer = fBuffer->data = SDDS_Malloc(sizeof(char) * (fBuffer->bufferSize + 1)))) {
1003 SDDS_SetError("Unable to do buffered read--allocation failure (SDDS_WriteNonNativeBinaryPage)");
1004 return 0;
1005 }
1006 fBuffer->bytesLeft = fBuffer->bufferSize;
1007 fBuffer->data[0] = 0;
1008 }
1009 if (fixed_rows > INT32_MAX) {
1010 SDDS_SwapLong(&min32);
1011 if (!SDDS_MPI_BufferedWrite(&min32, sizeof(min32), SDDS_dataset))
1012 return 0;
1013 SDDS_SwapLong64(&fixed_rows);
1014 if (!SDDS_MPI_BufferedWrite(&fixed_rows, sizeof(fixed_rows), SDDS_dataset))
1015 return 0;
1016 } else {
1017 int32_t fixed_rows32;
1018 fixed_rows32 = (int32_t)fixed_rows;
1019 SDDS_SwapLong(&fixed_rows32);
1020 if (!SDDS_MPI_BufferedWrite(&fixed_rows32, sizeof(fixed_rows32), SDDS_dataset))
1021 return 0;
1022 }
1024 return 0;
1025 /* flush buffer, write everything in the buffer to file */
1026 if (!SDDS_MPI_FlushBuffer(SDDS_dataset))
1027 return 0;
1028 }
1029 SDDS_SwapEndsColumnData(SDDS_dataset);
1030 if (SDDS_dataset->layout.data_mode.column_major) {
1031 /*write data by column */
1032 offset = rowcount_offset;
1033 for (i = 0; i < SDDS_dataset->layout.n_columns; i++) {
1034 type = SDDS_dataset->layout.column_definition[i].type;
1035 MPI_dataset->file_offset = offset + (MPI_Offset)prev_rows * SDDS_type_size[type - 1];
1036 if (type == SDDS_STRING) {
1037 SDDS_SetError("Can not write string column to SDDS3 (SDDS_MPI_WriteNonNativeBinaryPage");
1038 return 0;
1039 }
1040 if ((mpi_code = MPI_File_set_view(MPI_dataset->MPI_file, MPI_dataset->file_offset, MPI_BYTE, MPI_BYTE, "native", MPI_INFO_NULL)) != MPI_SUCCESS) {
1041 SDDS_MPI_GOTO_ERROR(stderr, "Unable to set view for read binary rows", mpi_code, 0);
1042 SDDS_SetError("Unable to set view for read binary rows");
1043 return 0;
1044 }
1045 if ((mpi_code = MPI_File_write(MPI_dataset->MPI_file, SDDS_dataset->data[i], rows * SDDS_type_size[type - 1], MPI_BYTE, &status)) != MPI_SUCCESS) {
1046 SDDS_SetError("Unable to write binary columns (SDDS_MPI_WriteNonNativeBinaryPage");
1047 return 0;
1048 }
1049
1050 offset += (MPI_Offset)total_rows * SDDS_type_size[type - 1];
1051 }
1052 MPI_dataset->file_offset = offset;
1053 } else {
1054 /* now all processors write column data row by row */
1055 MPI_dataset->file_offset = rowcount_offset + (MPI_Offset)prev_rows * column_offset;
1056 /* set view to the position where the processor starts writing data */
1057 MPI_File_set_view(MPI_dataset->MPI_file, MPI_dataset->file_offset, MPI_BYTE, MPI_BYTE, "native", MPI_INFO_NULL);
1058 if (!MPI_dataset->collective_io) {
1059 row = 0;
1060 for (i = 0; i < SDDS_dataset->n_rows; i++) {
1061 if (SDDS_dataset->row_flag[i] && !SDDS_MPI_WriteNonNativeBinaryRow(SDDS_dataset, i))
1062 return 0;
1063 row++;
1064 }
1065 /*get current file position until now */
1066 SDDS_dataset->n_rows = row;
1067 if (!SDDS_MPI_FlushBuffer(SDDS_dataset))
1068 return 0;
1069 } else {
1070 if (!SDDS_MPI_CollectiveWriteByRow(SDDS_dataset))
1071 return 0;
1072 row = SDDS_dataset->n_rows;
1073 }
1074 MPI_Allreduce(&row, &total_rows, 1, MPI_INT64_T, MPI_SUM, MPI_dataset->comm);
1075 MPI_dataset->file_offset = rowcount_offset + total_rows * column_offset;
1076 rows = row;
1077 }
1078 SDDS_SwapEndsColumnData(SDDS_dataset);
1079 free(n_rows);
1080 /*skip checking if all data has been written for now */
1081 SDDS_dataset->last_row_written = SDDS_dataset->n_rows - 1;
1082 SDDS_dataset->n_rows_written = rows;
1083 SDDS_dataset->writing_page = 1;
1084 MPI_dataset->n_page++;
1085 return 1;
1086}
1087
1088/**
1089 * @brief Write a continuous binary page of the SDDS dataset using MPI.
1090 *
1091 * This function writes an SDDS dataset page in binary format, handling both native
1092 * and non-native byte orders based on the environment variable `SDDS_OUTPUT_ENDIANESS`.
1093 * It manages buffer allocation, byte swapping, and coordinates writing across MPI processes.
1094 *
1095 * @param SDDS_dataset Pointer to the SDDS_DATASET structure.
1096 * @return
1097 * - `1` on successful write.
1098 * - `0` on failure.
1099 */
1101 int64_t row, prev_rows, i, total_rows, fixed_rows, rows;
1102 int mpi_code, type = 0;
1103 MPI_Offset column_offset, rowcount_offset, offset;
1104 int64_t *n_rows = NULL;
1105 int32_t min32 = INT32_MIN;
1106 MPI_Status status;
1107
1108 MPI_DATASET *MPI_dataset = NULL;
1109 SDDS_FILEBUFFER *fBuffer;
1110 char *outputEndianess = NULL;
1111
1112#if MPI_DEBUG
1113 logDebug("SDDS_MPI_WriteContinuousBinaryPage", SDDS_dataset);
1114#endif
1115
1116 /* usleep(10000); This doesn't really help */
1117
1118 if ((outputEndianess = getenv("SDDS_OUTPUT_ENDIANESS"))) {
1119 if (((strncmp(outputEndianess, "big", 3) == 0) && (SDDS_IsBigEndianMachine() == 0)) || ((strncmp(outputEndianess, "little", 6) == 0) && (SDDS_IsBigEndianMachine() == 1)))
1120 return SDDS_MPI_WriteNonNativeBinaryPage(SDDS_dataset);
1121 }
1122
1123 MPI_dataset = SDDS_dataset->MPI_dataset;
1124
1125 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_MPI_WriteContinuousBinaryPage"))
1126 return (0);
1127
1128 fBuffer = &SDDS_dataset->fBuffer;
1129 if (SDDS_dataset->layout.data_mode.column_major)
1130 /*write by column ignores the row flag and buffer is not needed for writing data by column */
1131 rows = SDDS_dataset->n_rows;
1132 else {
1133 rows = SDDS_CountRowsOfInterest(SDDS_dataset);
1134 if (!fBuffer->buffer) {
1135 fBuffer->bufferSize = SDDS_GetLockedDefaultWriteBufferSize();
1136 if (!(fBuffer->buffer = fBuffer->data = SDDS_Malloc(sizeof(char) * (fBuffer->bufferSize + 1)))) {
1137 SDDS_SetError("Unable to do buffered read--allocation failure (SDDS_WriteContinuousBinaryPage)");
1138 return 0;
1139 }
1140 fBuffer->bytesLeft = fBuffer->bufferSize;
1141 fBuffer->data[0] = 0;
1142 }
1143 }
1144 if (MPI_dataset->n_page >= 1)
1145 MPI_File_set_view(MPI_dataset->MPI_file, MPI_dataset->file_offset, MPI_BYTE, MPI_BYTE, "native", MPI_INFO_NULL);
1146 rowcount_offset = MPI_dataset->file_offset + SDDS_MPI_GetTitleOffset(SDDS_dataset); /* the offset before writing rows */
1147 /*get total number of rows writing */
1148 column_offset = MPI_dataset->column_offset;
1149 if (!(n_rows = calloc(sizeof(*n_rows), MPI_dataset->n_processors))) {
1150 SDDS_SetError("Memory allocation failed!");
1151 return 0;
1152 }
1153 MPI_Allgather(&rows, 1, MPI_INT64_T, n_rows, 1, MPI_INT64_T, MPI_dataset->comm);
1154 prev_rows = 0;
1155 for (i = 0; i < MPI_dataset->myid; i++)
1156 prev_rows += n_rows[i];
1157 total_rows = 0;
1158 for (i = 0; i < MPI_dataset->n_processors; i++)
1159 total_rows += n_rows[i];
1160 if (MPI_dataset->myid == 0) {
1161 fixed_rows = total_rows;
1162 if (!fBuffer->buffer) {
1163 fBuffer->bufferSize = SDDS_GetLockedDefaultWriteBufferSize();
1164 if (!(fBuffer->buffer = fBuffer->data = SDDS_Malloc(sizeof(char) * (fBuffer->bufferSize + 1)))) {
1165 SDDS_SetError("Unable to do buffered read--allocation failure (SDDS_WriteContinuousBinaryPage)");
1166 return 0;
1167 }
1168 fBuffer->bytesLeft = fBuffer->bufferSize;
1169 fBuffer->data[0] = 0;
1170 }
1171 if (fixed_rows > INT32_MAX) {
1172 if (!SDDS_MPI_BufferedWrite(&min32, sizeof(min32), SDDS_dataset))
1173 return 0;
1174 if (!SDDS_MPI_BufferedWrite(&fixed_rows, sizeof(fixed_rows), SDDS_dataset))
1175 return 0;
1176 } else {
1177 int32_t fixed_rows32;
1178 fixed_rows32 = (int32_t)fixed_rows;
1179 if (!SDDS_MPI_BufferedWrite(&fixed_rows32, sizeof(fixed_rows32), SDDS_dataset))
1180 return 0;
1181 }
1182 if (!SDDS_MPI_WriteBinaryParameters(SDDS_dataset) || !SDDS_MPI_WriteBinaryArrays(SDDS_dataset))
1183 return 0;
1184 /* flush buffer, write everything in the buffer to file */
1185 if (!SDDS_MPI_FlushBuffer(SDDS_dataset))
1186 return 0;
1187 }
1188
1189 if (SDDS_dataset->layout.data_mode.column_major) {
1190 /*write data by column */
1191 offset = rowcount_offset;
1192 for (i = 0; i < SDDS_dataset->layout.n_columns; i++) {
1193 type = SDDS_dataset->layout.column_definition[i].type;
1194 MPI_dataset->file_offset = offset + (MPI_Offset)prev_rows * SDDS_type_size[type - 1];
1195 if (type == SDDS_STRING) {
1196 SDDS_SetError("Can not write string column to SDDS3 (SDDS_MPI_WriteContinuousBinaryPage");
1197 return 0;
1198 }
1199 if ((mpi_code = MPI_File_set_view(MPI_dataset->MPI_file, MPI_dataset->file_offset, MPI_BYTE, MPI_BYTE, "native", MPI_INFO_NULL)) != MPI_SUCCESS) {
1200 SDDS_MPI_GOTO_ERROR(stderr, "Unable to set view for read binary rows", mpi_code, 0);
1201 SDDS_SetError("Unable to set view for read binary rows");
1202 return 0;
1203 }
1204 if ((mpi_code = MPI_File_write(MPI_dataset->MPI_file, SDDS_dataset->data[i], rows * SDDS_type_size[type - 1], MPI_BYTE, &status)) != MPI_SUCCESS) {
1205 SDDS_SetError("Unable to write binary columns (SDDS_MPI_WriteContinuousBinaryPage");
1206 return 0;
1207 }
1208
1209 offset += (MPI_Offset)total_rows * SDDS_type_size[type - 1];
1210 }
1211 MPI_dataset->file_offset = offset;
1212 } else {
1213 /* now all processors write column data row by row */
1214 MPI_dataset->file_offset = rowcount_offset + (MPI_Offset)prev_rows * column_offset;
1215 /* set view to the position where the processor starts writing data */
1216 MPI_File_set_view(MPI_dataset->MPI_file, MPI_dataset->file_offset, MPI_BYTE, MPI_BYTE, "native", MPI_INFO_NULL);
1217 if (!MPI_dataset->collective_io) {
1218 row = 0;
1219 for (i = 0; i < SDDS_dataset->n_rows; i++) {
1220 if (SDDS_dataset->row_flag[i] && !SDDS_MPI_WriteBinaryRow(SDDS_dataset, i))
1221 return 0;
1222 row++;
1223 }
1224 /*get current file position until now */
1225 SDDS_dataset->n_rows = row;
1226 if (!SDDS_MPI_FlushBuffer(SDDS_dataset))
1227 return 0;
1228 } else {
1229 if (!SDDS_MPI_CollectiveWriteByRow(SDDS_dataset))
1230 return 0;
1231 row = SDDS_dataset->n_rows;
1232 }
1233 MPI_Allreduce(&row, &total_rows, 1, MPI_INT64_T, MPI_SUM, MPI_dataset->comm);
1234 MPI_dataset->file_offset = rowcount_offset + total_rows * column_offset;
1235 rows = row;
1236 }
1237 free(n_rows);
1238 /*skip checking if all data has been written for now */
1239 SDDS_dataset->last_row_written = SDDS_dataset->n_rows - 1;
1240 SDDS_dataset->n_rows_written = rows;
1241 SDDS_dataset->writing_page = 1;
1242 MPI_dataset->n_page++;
1243
1244 return 1;
1245}
1246
1247/**
1248 * @brief Buffered read from an SDDS dataset using MPI.
1249 *
1250 * This function reads data from the SDDS dataset using a buffer. It handles cases
1251 * where sufficient data is already in the buffer and cases where additional data
1252 * needs to be read from the MPI file. It also manages end-of-file conditions.
1253 *
1254 * @param target Pointer to the buffer where the read data will be stored.
1255 * @param targetSize The size of the data to read, in bytes.
1256 * @param SDDS_dataset Pointer to the SDDS_DATASET structure.
1257 * @param fBuffer Pointer to the SDDS_FILEBUFFER structure managing the buffer.
1258 * @return
1259 * - `1` on successful read.
1260 * - `0` on partial read or failure.
1261 * - `-1` if end-of-file is reached.
1262 */
1263int32_t SDDS_MPI_BufferedRead(void *target, int64_t targetSize, SDDS_DATASET *SDDS_dataset, SDDS_FILEBUFFER *fBuffer) {
1264 int32_t mpi_code;
1265 int32_t bytesRead, count;
1266 MPI_Status status;
1267 MPI_DATASET *MPI_dataset = SDDS_dataset->MPI_dataset;
1268
1269 if (!fBuffer || !fBuffer->bufferSize) {
1270 /* just read into users buffer or seek if no buffer given */
1271 if (!target)
1272 mpi_code = MPI_File_seek(MPI_dataset->MPI_file, targetSize, MPI_SEEK_CUR);
1273 else {
1274 mpi_code = MPI_File_read(MPI_dataset->MPI_file, target, targetSize, MPI_BYTE, &status);
1275 MPI_Get_count(&status, MPI_BYTE, &bytesRead);
1276 if (!bytesRead) {
1277 MPI_dataset->end_of_file = 1;
1278 return -1;
1279 }
1280 if (bytesRead < targetSize)
1281 return 0;
1282 }
1283 if (mpi_code != MPI_SUCCESS) {
1284 SDDS_MPI_GOTO_ERROR(stderr, "SDDS_MPI_BufferedRead(MPI_File_read failed)", mpi_code, 0);
1285 return 0;
1286 }
1287 return 1;
1288 }
1289 if ((fBuffer->bytesLeft -= targetSize) >= 0) {
1290 /* sufficient data is already in the buffer */
1291 if (target && targetSize > 0) {
1292 memcpy((char *)target, (char *)fBuffer->data, (size_t)targetSize);
1293 }
1294 fBuffer->data += targetSize;
1295 return 1;
1296 } else {
1297 /* need to read additional data into buffer */
1298 int64_t bytesNeeded, offset;
1299 fBuffer->bytesLeft += targetSize; /* adds back amount subtracted above */
1300 /* first, use the data that is already available. this cleans out the buffer */
1301 if ((offset = fBuffer->bytesLeft)) {
1302 /* some data is available in the buffer */
1303 if (target && offset > 0) {
1304 memcpy((char *)target, (char *)fBuffer->data, (size_t)offset);
1305 }
1306 bytesNeeded = targetSize - offset;
1307 fBuffer->bytesLeft = 0;
1308 } else {
1309 bytesNeeded = targetSize;
1310 }
1311 fBuffer->data = fBuffer->buffer;
1312 if (fBuffer->bufferSize < bytesNeeded) {
1313 /* just read what is needed directly into user's memory or seek */
1314 if (!target)
1315 mpi_code = MPI_File_seek(MPI_dataset->MPI_file, targetSize, MPI_SEEK_CUR);
1316 else {
1317 mpi_code = MPI_File_read(MPI_dataset->MPI_file, (char *)target + offset, bytesNeeded, MPI_BYTE, &status);
1318 MPI_Get_count(&status, MPI_BYTE, &bytesRead);
1319 if (!bytesRead) {
1320 MPI_dataset->end_of_file = 1;
1321 return -1;
1322 }
1323 if (bytesRead < bytesNeeded)
1324 return 0;
1325 }
1326 if (mpi_code != MPI_SUCCESS) {
1327 SDDS_MPI_GOTO_ERROR(stderr, "SDDS_MPI_ReadBufferedRead(MPI_File_read failed)", mpi_code, 0);
1328 return 0;
1329 }
1330 return 1;
1331 }
1332 /* fill the buffer */
1333 mpi_code = MPI_File_read(MPI_dataset->MPI_file, fBuffer->data, (int)(fBuffer->bufferSize), MPI_BYTE, &status);
1334 MPI_Get_count(&status, MPI_BYTE, &count);
1335 fBuffer->bytesLeft = count;
1336 if (!(fBuffer->bytesLeft))
1337 MPI_dataset->end_of_file = 1;
1338 if (fBuffer->bytesLeft < bytesNeeded)
1339 return 0;
1340 if (target && bytesNeeded > 0)
1341 memcpy((char *)target + offset, (char *)fBuffer->data, (size_t)bytesNeeded);
1342 fBuffer->data += bytesNeeded;
1343 fBuffer->bytesLeft -= bytesNeeded;
1344 return 1;
1345 }
1346}
1347
1348/**
1349 * @brief Buffered read all from an SDDS dataset using MPI.
1350 *
1351 * This function reads all requested data from the SDDS dataset using a buffer,
1352 * ensuring that the entire requested data is read unless end-of-file is reached.
1353 * It handles buffer management and MPI collective I/O operations.
1354 *
1355 * @param target Pointer to the buffer where the read data will be stored.
1356 * @param targetSize The size of the data to read, in bytes.
1357 * @param SDDS_dataset Pointer to the SDDS_DATASET structure.
1358 * @param fBuffer Pointer to the SDDS_FILEBUFFER structure managing the buffer.
1359 * @return
1360 * - `1` on successful read of all requested data.
1361 * - `0` on partial read or failure.
1362 * - `-1` if end-of-file is reached.
1363 */
1364int32_t SDDS_MPI_BufferedReadAll(void *target, int64_t targetSize, SDDS_DATASET *SDDS_dataset, SDDS_FILEBUFFER *fBuffer) {
1365 int32_t mpi_code, bytesRead, count;
1366 MPI_Status status;
1367 MPI_DATASET *MPI_dataset = SDDS_dataset->MPI_dataset;
1368
1369 if (!fBuffer || !fBuffer->bufferSize) {
1370 /* just read into users buffer or seek if no buffer given */
1371 if (!target)
1372 mpi_code = MPI_File_seek(MPI_dataset->MPI_file, targetSize, MPI_SEEK_CUR);
1373 else {
1374 mpi_code = MPI_File_read_all(MPI_dataset->MPI_file, target, targetSize, MPI_BYTE, &status);
1375 MPI_Get_count(&status, MPI_BYTE, &bytesRead);
1376 if (!bytesRead) {
1377 MPI_dataset->end_of_file = 1;
1378 return -1;
1379 }
1380 if (bytesRead < targetSize)
1381 return 0;
1382 }
1383 if (mpi_code != MPI_SUCCESS) {
1384 SDDS_MPI_GOTO_ERROR(stderr, "SDDS_MPI_BufferedRead(MPI_File_read failed)", mpi_code, 0);
1385 return 0;
1386 }
1387 return 1;
1388 }
1389 if ((fBuffer->bytesLeft -= targetSize) >= 0) {
1390 /* sufficient data is already in the buffer */
1391 if (target && targetSize > 0) {
1392 memcpy((char *)target, (char *)fBuffer->data, (size_t)targetSize);
1393 }
1394 fBuffer->data += targetSize;
1395 return 1;
1396 } else {
1397 /* need to read additional data into buffer */
1398 int64_t bytesNeeded, offset;
1399 fBuffer->bytesLeft += targetSize; /* adds back amount subtracted above */
1400 /* first, use the data that is already available. this cleans out the buffer */
1401 if ((offset = fBuffer->bytesLeft)) {
1402 /* some data is available in the buffer */
1403 if (target && offset > 0) {
1404 memcpy((char *)target, (char *)fBuffer->data, (size_t)offset);
1405 }
1406 bytesNeeded = targetSize - offset;
1407 fBuffer->bytesLeft = 0;
1408 } else {
1409 bytesNeeded = targetSize;
1410 }
1411 fBuffer->data = fBuffer->buffer;
1412 if (fBuffer->bufferSize < bytesNeeded) {
1413 /* just read what is needed directly into user's memory or seek */
1414 if (!target)
1415 mpi_code = MPI_File_seek(MPI_dataset->MPI_file, targetSize, MPI_SEEK_CUR);
1416 else {
1417 mpi_code = MPI_File_read_all(MPI_dataset->MPI_file, (char *)target + offset, bytesNeeded, MPI_BYTE, &status);
1418 MPI_Get_count(&status, MPI_BYTE, &bytesRead);
1419 if (!bytesRead) {
1420 MPI_dataset->end_of_file = 1;
1421 return -1;
1422 }
1423 if (bytesRead < bytesNeeded)
1424 return 0;
1425 }
1426 if (mpi_code != MPI_SUCCESS) {
1427 SDDS_MPI_GOTO_ERROR(stderr, "SDDS_MPI_ReadBufferedRead(MPI_File_read failed)", mpi_code, 0);
1428 return 0;
1429 }
1430 return 1;
1431 }
1432 /* fill the buffer */
1433 mpi_code = MPI_File_read_all(MPI_dataset->MPI_file, fBuffer->data, (int)(fBuffer->bufferSize), MPI_BYTE, &status);
1434 MPI_Get_count(&status, MPI_BYTE, &count);
1435 fBuffer->bytesLeft = count;
1436 if (!(fBuffer->bytesLeft))
1437 MPI_dataset->end_of_file = 1;
1438 if (fBuffer->bytesLeft < bytesNeeded)
1439 return 0;
1440 if (target && bytesNeeded > 0)
1441 memcpy((char *)target + offset, (char *)fBuffer->data, (size_t)bytesNeeded);
1442 fBuffer->data += bytesNeeded;
1443 fBuffer->bytesLeft -= bytesNeeded;
1444 return 1;
1445 }
1446}
1447
1448/**
1449 * @brief Read a binary string from the SDDS dataset using MPI.
1450 *
1451 * This function reads a string from the SDDS dataset in binary format using MPI.
1452 * It first reads the length of the string, allocates memory for the string,
1453 * and then reads the string data itself. If the `skip` parameter is set,
1454 * the string data is read and discarded.
1455 *
1456 * @param SDDS_dataset Pointer to the SDDS_DATASET structure.
1457 * @param fBuffer Pointer to the SDDS_FILEBUFFER structure managing the buffer.
1458 * @param skip If non-zero, the string data is read and skipped (not stored).
1459 * @return
1460 * - Pointer to the allocated string on success.
1461 * - `0` if reading the length fails or if the length is negative.
1462 * - `NULL` if memory allocation fails or reading the string data fails.
1463 */
1464char *SDDS_MPI_ReadBinaryString(SDDS_DATASET *SDDS_dataset, SDDS_FILEBUFFER *fBuffer, int32_t skip) {
1465 int32_t length;
1466 char *string;
1467 if (!SDDS_MPI_BufferedRead(&length, sizeof(length), SDDS_dataset, fBuffer) || length < 0)
1468 return (0);
1469 if (!(string = SDDS_Malloc(sizeof(*string) * (length + 1))))
1470 return (NULL);
1471 if (length && !SDDS_MPI_BufferedRead(skip ? NULL : string, sizeof(*string) * length, SDDS_dataset, fBuffer))
1472 return (NULL);
1473 string[length] = 0;
1474 return (string);
1475}
1476
1477/**
1478 * @brief Read a non-native binary string from the SDDS dataset using MPI.
1479 *
1480 * This function reads a string from the SDDS dataset in non-native binary format using MPI.
1481 * It handles byte swapping for the string length to match the non-native byte order.
1482 * After reading the length, it allocates memory for the string and reads the string data.
1483 * If the `skip` parameter is set, the string data is read and discarded.
1484 *
1485 * @param SDDS_dataset Pointer to the SDDS_DATASET structure.
1486 * @param fBuffer Pointer to the SDDS_FILEBUFFER structure managing the buffer.
1487 * @param skip If non-zero, the string data is read and skipped (not stored).
1488 * @return
1489 * - Pointer to the allocated string on success.
1490 * - `0` if reading the length fails or if the length is negative.
1491 * - `NULL` if memory allocation fails or reading the string data fails.
1492 */
1493char *SDDS_MPI_ReadNonNativeBinaryString(SDDS_DATASET *SDDS_dataset, SDDS_FILEBUFFER *fBuffer, int32_t skip) {
1494 int32_t length;
1495 char *string;
1496
1497 if (!SDDS_MPI_BufferedRead(&length, sizeof(length), SDDS_dataset, fBuffer))
1498 return (0);
1499 SDDS_SwapLong(&length);
1500 if (length < 0)
1501 return (0);
1502 if (!(string = SDDS_Malloc(sizeof(*string) * (length + 1))))
1503 return (NULL);
1504 if (length && !SDDS_MPI_BufferedRead(skip ? NULL : string, sizeof(*string) * length, SDDS_dataset, fBuffer))
1505 return (NULL);
1506 string[length] = 0;
1507 return (string);
1508}
1509
1510/**
1511 * @brief Read binary parameters from the SDDS dataset using MPI.
1512 *
1513 * This function reads all non-fixed parameters from the SDDS dataset in binary format using MPI.
1514 * It iterates through each parameter, handling string parameters by reading them as binary strings,
1515 * and other types by reading their binary representations directly into the dataset's parameter storage.
1516 *
1517 * @param SDDS_dataset Pointer to the SDDS_DATASET structure.
1518 * @param fBuffer Pointer to the SDDS_FILEBUFFER structure managing the buffer.
1519 * @return
1520 * - `1` on successful read of all parameters.
1521 * - `0` on failure to read any parameter.
1522 */
1524 int32_t i;
1525 SDDS_LAYOUT *layout;
1526 /* char *predefined_format; */
1527 char buffer[SDDS_MAXLINE];
1528
1529 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_MPI_ReadBinaryParameters"))
1530 return (0);
1531 layout = &SDDS_dataset->layout;
1532 if (!layout->n_parameters)
1533 return (1);
1534 for (i = 0; i < layout->n_parameters; i++) {
1535 if (layout->parameter_definition[i].definition_mode & SDDS_WRITEONLY_DEFINITION)
1536 continue;
1537 if (layout->parameter_definition[i].fixed_value) {
1538 strcpy(buffer, layout->parameter_definition[i].fixed_value);
1539 if (!SDDS_ScanData(buffer, layout->parameter_definition[i].type, 0, SDDS_dataset->parameter[i], 0, 1)) {
1540 SDDS_SetError("Unable to read page--parameter scanning error (SDDS_MPI_ReadBinaryParameters)");
1541 return (0);
1542 }
1543 } else if (layout->parameter_definition[i].type == SDDS_STRING) {
1544 if (*(char **)SDDS_dataset->parameter[i])
1545 free(*(char **)SDDS_dataset->parameter[i]);
1546 if (!(*((char **)SDDS_dataset->parameter[i]) = SDDS_MPI_ReadBinaryString(SDDS_dataset, fBuffer, 0))) {
1547 SDDS_SetError("Unable to read parameters--failure reading string (SDDS_MPI_ReadBinaryParameters)");
1548 return (0);
1549 }
1550 } else {
1551 if (!SDDS_MPI_BufferedRead(SDDS_dataset->parameter[i], SDDS_type_size[layout->parameter_definition[i].type - 1], SDDS_dataset, fBuffer)) {
1552 SDDS_SetError("Unable to read parameters--failure reading value (SDDS_MPI_ReadBinaryParameters)");
1553 return (0);
1554 }
1555 }
1556 }
1557 return (1);
1558}
1559
1560/**
1561 * @brief Read a binary row from the SDDS dataset using MPI.
1562 *
1563 * This function reads a specific row of data from the SDDS dataset in binary format using MPI.
1564 * It handles different column types, including strings and fixed-size data types. If the `skip` parameter
1565 * is set, string data is read and discarded.
1566 *
1567 * @param SDDS_dataset Pointer to the SDDS_DATASET structure.
1568 * @param row The row index to read.
1569 * @param skip If non-zero, string data in the row is read but not stored.
1570 * @return
1571 * - `1` on successful read of the row.
1572 * - `0` on failure to read any part of the row.
1573 */
1574int32_t SDDS_MPI_ReadBinaryRow(SDDS_DATASET *SDDS_dataset, int64_t row, int32_t skip) {
1575 int64_t i;
1576 int32_t type, size;
1577 SDDS_LAYOUT *layout;
1578 SDDS_FILEBUFFER *fBuffer;
1579
1580 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_MPI_ReadBinaryRow"))
1581 return (0);
1582 layout = &SDDS_dataset->layout;
1583 fBuffer = &SDDS_dataset->fBuffer;
1584
1585 for (i = 0; i < layout->n_columns; i++) {
1586 if (layout->column_definition[i].definition_mode & SDDS_WRITEONLY_DEFINITION)
1587 continue;
1588 if ((type = layout->column_definition[i].type) == SDDS_STRING) {
1589 if (!skip) {
1590 if (((char ***)SDDS_dataset->data)[i][row])
1591 free((((char ***)SDDS_dataset->data)[i][row]));
1592 if (!(((char ***)SDDS_dataset->data)[i][row] = SDDS_MPI_ReadBinaryString(SDDS_dataset, fBuffer, 0))) {
1593 SDDS_SetError("Unable to read rows--failure reading string (SDDS_MPI_ReadBinaryRows)");
1594 return (0);
1595 }
1596 } else {
1597 if (!(((char ***)SDDS_dataset->data)[i][row] = SDDS_MPI_ReadBinaryString(SDDS_dataset, fBuffer, 1))) {
1598 SDDS_SetError("Unable to read rows--failure reading string (SDDS_MPI_ReadBinaryRows)");
1599 return 0;
1600 }
1601 }
1602 } else {
1603 size = SDDS_type_size[type - 1];
1604 if (!SDDS_MPI_BufferedRead(skip ? NULL : (char *)SDDS_dataset->data[i] + row * size, size, SDDS_dataset, fBuffer)) {
1605 SDDS_SetError("Unable to read row--failure reading value (SDDS_MPI_ReadBinaryRow)");
1606 return (0);
1607 }
1608 }
1609 }
1610 return (1);
1611}
1612
1613/**
1614 * @brief Read binary arrays from the SDDS dataset using MPI.
1615 *
1616 * This function reads all arrays defined in the SDDS dataset in binary format using MPI.
1617 * It handles reading array dimensions, allocating memory for array data, and reading
1618 * the actual array data. For string arrays, it reads each string individually.
1619 *
1620 * @param SDDS_dataset Pointer to the SDDS_DATASET structure.
1621 * @param fBuffer Pointer to the SDDS_FILEBUFFER structure managing the buffer.
1622 * @return
1623 * - `1` on successful read of all arrays.
1624 * - `0` on failure to read any part of the arrays.
1625 */
1627 int32_t i, j;
1628 SDDS_LAYOUT *layout;
1629 /* char *predefined_format; */
1630 /* static char buffer[SDDS_MAXLINE]; */
1631 SDDS_ARRAY *array;
1632
1633 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_MPI_ReadBinaryArrays"))
1634 return (0);
1635 layout = &SDDS_dataset->layout;
1636 if (!layout->n_arrays)
1637 return (1);
1638
1639 if (!SDDS_dataset->array) {
1640 SDDS_SetError("Unable to read array--pointer to structure storage area is NULL (SDDS_MPI_ReadBinaryArrays)");
1641 return (0);
1642 }
1643 for (i = 0; i < layout->n_arrays; i++) {
1644 array = SDDS_dataset->array + i;
1645 if (array->definition && !SDDS_FreeArrayDefinition(array->definition)) {
1646 SDDS_SetError("Unable to get array--array definition corrupted (SDDS_MPI_ReadBinaryArrays)");
1647 return (0);
1648 }
1649 if (!SDDS_CopyArrayDefinition(&array->definition, layout->array_definition + i)) {
1650 SDDS_SetError("Unable to read array--definition copy failed (SDDS_MPI_ReadBinaryArrays)");
1651 return (0);
1652 }
1653 /*if (array->dimension) free(array->dimension); */
1654 if (!(array->dimension = SDDS_Realloc(array->dimension, sizeof(*array->dimension) * array->definition->dimensions))) {
1655 SDDS_SetError("Unable to read array--allocation failure (SDDS_MPI_ReadBinaryArrays)");
1656 return (0);
1657 }
1658 if (!SDDS_MPI_BufferedRead(array->dimension, sizeof(*array->dimension) * array->definition->dimensions, SDDS_dataset, fBuffer)) {
1659 SDDS_SetError("Unable to read arrays--failure reading dimensions (SDDS_MPI_ReadBinaryArrays)");
1660 return (0);
1661 }
1662 array->elements = 1;
1663 for (j = 0; j < array->definition->dimensions; j++)
1664 array->elements *= array->dimension[j];
1665 if (array->data)
1666 free(array->data);
1667 array->data = array->pointer = NULL;
1668 if (array->elements == 0)
1669 continue;
1670 if (array->elements < 0) {
1671 SDDS_SetError("Unable to read array--number of elements is negative (SDDS_MPI_ReadBinaryArrays)");
1672 return (0);
1673 }
1674 if (!(array->data = SDDS_Realloc(array->data, array->elements * SDDS_type_size[array->definition->type - 1]))) {
1675 SDDS_SetError("Unable to read array--allocation failure (SDDS_MPI_ReadBinaryArrays)");
1676 return (0);
1677 }
1678 if (array->definition->type == SDDS_STRING) {
1679 for (j = 0; j < array->elements; j++) {
1680 if (!(((char **)(array->data))[j] = SDDS_MPI_ReadBinaryString(SDDS_dataset, fBuffer, 0))) {
1681 SDDS_SetError("Unable to read arrays--failure reading string (SDDS_MPI_ReadBinaryArrays)");
1682 return (0);
1683 }
1684 }
1685 } else {
1686 if (!SDDS_MPI_BufferedRead(array->data, SDDS_type_size[array->definition->type - 1] * array->elements, SDDS_dataset, fBuffer)) {
1687 SDDS_SetError("Unable to read arrays--failure reading values (SDDS_MPI_ReadBinaryArrays)");
1688 return (0);
1689 }
1690 }
1691 }
1692 return (1);
1693}
1694
1695/**
1696 * @brief Read non-native binary parameters from the SDDS dataset using MPI.
1697 *
1698 * This function reads all non-fixed parameters from the SDDS dataset in non-native
1699 * binary format using MPI. It handles byte swapping for parameter data to match
1700 * the non-native byte order. String parameters are read as non-native binary strings,
1701 * and other types are read directly into the dataset's parameter storage.
1702 *
1703 * @param SDDS_dataset Pointer to the SDDS_DATASET structure.
1704 * @param fBuffer Pointer to the SDDS_FILEBUFFER structure managing the buffer.
1705 * @return
1706 * - `1` on successful read of all parameters.
1707 * - `0` on failure to read any parameter.
1708 */
1710 int32_t i;
1711 SDDS_LAYOUT *layout;
1712 char buffer[SDDS_MAXLINE];
1713
1714 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_MPI_ReadNonNativeBinaryParameters"))
1715 return (0);
1716 layout = &SDDS_dataset->layout;
1717 if (!layout->n_parameters)
1718 return (1);
1719 for (i = 0; i < layout->n_parameters; i++) {
1720 if (layout->parameter_definition[i].definition_mode & SDDS_WRITEONLY_DEFINITION)
1721 continue;
1722 if (layout->parameter_definition[i].fixed_value) {
1723 strcpy(buffer, layout->parameter_definition[i].fixed_value);
1724 if (!SDDS_ScanData(buffer, layout->parameter_definition[i].type, 0, SDDS_dataset->parameter[i], 0, 1)) {
1725 SDDS_SetError("Unable to read page--parameter scanning error (SDDS_MPI_ReadNonNativeBinaryParameters)");
1726 return (0);
1727 }
1728 } else if (layout->parameter_definition[i].type == SDDS_STRING) {
1729 if (*(char **)SDDS_dataset->parameter[i])
1730 free(*(char **)SDDS_dataset->parameter[i]);
1731 if (!(*((char **)SDDS_dataset->parameter[i]) = SDDS_MPI_ReadNonNativeBinaryString(SDDS_dataset, fBuffer, 0))) {
1732 SDDS_SetError("Unable to read parameters--failure reading string (SDDS_MPI_ReadNonNativeBinaryParameters)");
1733 return (0);
1734 }
1735 } else {
1736 if (!SDDS_MPI_BufferedRead(SDDS_dataset->parameter[i], SDDS_type_size[layout->parameter_definition[i].type - 1], SDDS_dataset, fBuffer)) {
1737 SDDS_SetError("Unable to read parameters--failure reading value (SDDS_MPI_ReadNonNativeBinaryParameters)");
1738 return (0);
1739 }
1740 }
1741 }
1742 SDDS_SwapEndsParameterData(SDDS_dataset);
1743 return (1);
1744}
1745
1746/**
1747 * @brief Reads non-native binary arrays from a binary file buffer into the SDDS dataset using MPI.
1748 *
1749 * This function validates the provided SDDS dataset and reads array definitions and data from a non-native binary file buffer.
1750 * It handles byte swapping for endianness, allocates memory for array dimensions and data, and processes string arrays individually.
1751 *
1752 * @param[in,out] SDDS_dataset Pointer to the SDDS_DATASET structure where the arrays will be stored.
1753 * @param[in] fBuffer Pointer to the SDDS_FILEBUFFER structure containing the binary data to be read.
1754 *
1755 * @return int32_t Returns 1 on successful read, 0 on failure.
1756 */
1758 int32_t i, j;
1759 SDDS_LAYOUT *layout;
1760 SDDS_ARRAY *array;
1761
1762 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_MPI_ReadNonNativeBinaryArrays"))
1763 return (0);
1764 layout = &SDDS_dataset->layout;
1765 if (!layout->n_arrays)
1766 return (1);
1767
1768 if (!SDDS_dataset->array) {
1769 SDDS_SetError("Unable to read array--pointer to structure storage area is NULL (SDDS_MPI_ReadNonNativeBinaryArrays)");
1770 return (0);
1771 }
1772 for (i = 0; i < layout->n_arrays; i++) {
1773 array = SDDS_dataset->array + i;
1774 if (array->definition && !SDDS_FreeArrayDefinition(array->definition)) {
1775 SDDS_SetError("Unable to get array--array definition corrupted (SDDS_MPI_ReadNonNativeBinaryArrays)");
1776 return (0);
1777 }
1778 if (!SDDS_CopyArrayDefinition(&array->definition, layout->array_definition + i)) {
1779 SDDS_SetError("Unable to read array--definition copy failed (SDDS_MPI_ReadNonNativeBinaryArrays)");
1780 return (0);
1781 }
1782 /*if (array->dimension) free(array->dimension); */
1783 if (!(array->dimension = SDDS_Realloc(array->dimension, sizeof(*array->dimension) * array->definition->dimensions))) {
1784 SDDS_SetError("Unable to read array--allocation failure (SDDS_MPI_ReadNonNativeBinaryArrays)");
1785 return (0);
1786 }
1787 if (!SDDS_MPI_BufferedRead(array->dimension, sizeof(*array->dimension) * array->definition->dimensions, SDDS_dataset, fBuffer)) {
1788 SDDS_SetError("Unable to read arrays--failure reading dimensions (SDDS_MPI_ReadNonNativeBinaryArrays)");
1789 return (0);
1790 }
1791 SDDS_SwapLong(array->dimension);
1792 array->elements = 1;
1793 for (j = 0; j < array->definition->dimensions; j++)
1794 array->elements *= array->dimension[j];
1795 if (array->data)
1796 free(array->data);
1797 array->data = array->pointer = NULL;
1798 if (array->elements == 0)
1799 continue;
1800 if (array->elements < 0) {
1801 SDDS_SetError("Unable to read array--number of elements is negative (SDDS_MPI_ReadNonNativeBinaryArrays)");
1802 return (0);
1803 }
1804 if (!(array->data = SDDS_Realloc(array->data, array->elements * SDDS_type_size[array->definition->type - 1]))) {
1805 SDDS_SetError("Unable to read array--allocation failure (SDDS_MPI_ReadNonNativeBinaryArrays)");
1806 return (0);
1807 }
1808 if (array->definition->type == SDDS_STRING) {
1809 for (j = 0; j < array->elements; j++) {
1810 if (!(((char **)(array->data))[j] = SDDS_MPI_ReadNonNativeBinaryString(SDDS_dataset, fBuffer, 0))) {
1811 SDDS_SetError("Unable to read arrays--failure reading string (SDDS_MPI_ReadNonNativeBinaryArrays)");
1812 return (0);
1813 }
1814 }
1815 } else {
1816 if (!SDDS_MPI_BufferedRead(array->data, SDDS_type_size[array->definition->type - 1] * array->elements, SDDS_dataset, fBuffer)) {
1817 SDDS_SetError("Unable to read arrays--failure reading values (SDDS_MPI_ReadNonNativeBinaryArrays)");
1818 return (0);
1819 }
1820 }
1821 }
1822 SDDS_SwapEndsArrayData(SDDS_dataset);
1823 return (1);
1824}
1825
1826/**
1827 * @brief Reads a single non-native binary row from a binary file buffer into the SDDS dataset using MPI.
1828 *
1829 * This function reads the data for a specific row from the binary file buffer. It handles different data types, including strings,
1830 * and can optionally skip reading the row data. If skipping, it advances the file buffer without storing the data.
1831 *
1832 * @param[in,out] SDDS_dataset Pointer to the SDDS_DATASET structure where the row data will be stored.
1833 * @param[in] row The index of the row to read.
1834 * @param[in] skip If non-zero, the function will skip reading the row data without storing it.
1835 *
1836 * @return int32_t Returns 1 on successful read, 0 on failure.
1837 */
1838int32_t SDDS_MPI_ReadNonNativeBinaryRow(SDDS_DATASET *SDDS_dataset, int64_t row, int32_t skip) {
1839 int64_t i;
1840 int32_t type, size;
1841 SDDS_LAYOUT *layout;
1842 SDDS_FILEBUFFER *fBuffer;
1843
1844 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_MPI_ReadNonNativeBinaryRow"))
1845 return (0);
1846 layout = &SDDS_dataset->layout;
1847 fBuffer = &SDDS_dataset->fBuffer;
1848
1849 for (i = 0; i < layout->n_columns; i++) {
1850 if (layout->column_definition[i].definition_mode & SDDS_WRITEONLY_DEFINITION)
1851 continue;
1852 if ((type = layout->column_definition[i].type) == SDDS_STRING) {
1853 if (!skip) {
1854 if (((char ***)SDDS_dataset->data)[i][row])
1855 free((((char ***)SDDS_dataset->data)[i][row]));
1856 if (!(((char ***)SDDS_dataset->data)[i][row] = SDDS_MPI_ReadNonNativeBinaryString(SDDS_dataset, fBuffer, 0))) {
1857 SDDS_SetError("Unable to read rows--failure reading string (SDDS_MPI_ReadNonNativeBinaryRow)");
1858 return (0);
1859 }
1860 } else {
1861 if (!SDDS_MPI_ReadNonNativeBinaryString(SDDS_dataset, fBuffer, 1)) {
1862 SDDS_SetError("Unable to read rows--failure reading string (SDDS_MPI_ReadNonNativeBinaryRow)");
1863 return 0;
1864 }
1865 }
1866 } else {
1867 size = SDDS_type_size[type - 1];
1868 if (!SDDS_MPI_BufferedRead(skip ? NULL : (char *)SDDS_dataset->data[i] + row * size, size, SDDS_dataset, fBuffer)) {
1869 SDDS_SetError("Unable to read row--failure reading value (SDDS_MPI_ReadNonNativeBinaryRow)");
1870 return (0);
1871 }
1872 }
1873 }
1874 return (1);
1875}
1876
1877/**
1878 * @brief Broadcasts the title data (parameters and arrays) of the SDDS dataset to all MPI processes.
1879 *
1880 * This function gathers the title data from the master process and broadcasts it to all other MPI processes.
1881 * It handles the total number of rows, parameters, and array definitions, ensuring that each process has consistent dataset metadata.
1882 *
1883 * @param[in,out] SDDS_dataset Pointer to the SDDS_DATASET structure containing the title data to broadcast.
1884 *
1885 * @return int32_t Returns 1 on successful broadcast, 0 on failure.
1886 */
1888 char *par_data = NULL;
1889 int32_t type, size;
1890 int64_t i, count = 0, *data_len = NULL;
1891 MPI_DATASET *MPI_dataset;
1892 SDDS_LAYOUT *layout;
1893 char *string = NULL;
1894
1895 MPI_dataset = SDDS_dataset->MPI_dataset;
1896 layout = &(SDDS_dataset->layout);
1897 if (!layout->n_parameters && !layout->n_arrays) {
1898 /* no parameters and arrays, only broadcast total_rows */
1899 MPI_Bcast(&(MPI_dataset->total_rows), 1, MPI_INT64_T, 0, MPI_dataset->comm);
1900 } else {
1901 /* broadcast the total_rows and parameter data */
1902 data_len = calloc(sizeof(*data_len), 1 + layout->n_parameters);
1903 if (MPI_dataset->myid == 0) {
1904 data_len[0] = sizeof(int64_t);
1905 count = data_len[0];
1906 for (i = 0; i < layout->n_parameters; i++) {
1907 type = layout->parameter_definition[i].type;
1908 if (type == SDDS_STRING)
1909 data_len[i + 1] = strlen(*((char **)SDDS_dataset->parameter[i])) * sizeof(char);
1910 else
1911 data_len[i + 1] = SDDS_type_size[type - 1];
1912 ;
1913 count += data_len[i + 1];
1914 }
1915 par_data = (char *)malloc(sizeof(char) * count);
1916 memcpy((char *)par_data, &(MPI_dataset->total_rows), data_len[0]);
1917 count = data_len[0];
1918 for (i = 0; i < layout->n_parameters; i++) {
1919 if (layout->parameter_definition[i].type == SDDS_STRING)
1920 memcpy((char *)par_data + count, *(char **)SDDS_dataset->parameter[i], data_len[i + 1]);
1921 else
1922 memcpy((char *)par_data + count, (char *)SDDS_dataset->parameter[i], data_len[i + 1]);
1923 count += data_len[i + 1];
1924 }
1925 }
1926 MPI_Bcast(data_len, 1 + layout->n_parameters, MPI_INT64_T, 0, MPI_dataset->comm);
1927 if (MPI_dataset->myid) {
1928 count = data_len[0];
1929 for (i = 0; i < layout->n_parameters; i++)
1930 count += data_len[i + 1];
1931 par_data = (char *)malloc(sizeof(char) * count);
1932 }
1933
1934 MPI_Bcast(par_data, count, MPI_BYTE, 0, MPI_dataset->comm);
1935 if (!SDDS_StartPage(SDDS_dataset, 0)) {
1936 SDDS_SetError("Unable to read page--couldn't start page (SDDS_MPI_BroadcastTitleData)");
1937 return (0);
1938 }
1939 if (MPI_dataset->myid) {
1940 memcpy(&(MPI_dataset->total_rows), (char *)par_data, data_len[0]);
1941 count = data_len[0];
1942 for (i = 0; i < layout->n_parameters; i++) {
1943 if (layout->parameter_definition[i].type == SDDS_STRING) {
1944 string = malloc(sizeof(char) * (data_len[i + 1] + 1));
1945 memcpy((char *)string, (char *)par_data + count, data_len[i + 1]);
1946 string[data_len[i + 1]] = '\0';
1947 *(char **)SDDS_dataset->parameter[i] = string;
1948 } else
1949 memcpy((char *)(SDDS_dataset->parameter[i]), (char *)par_data + count, data_len[i + 1]);
1950 count += data_len[i + 1];
1951 }
1952 }
1953 }
1954 free(data_len);
1955 free(par_data);
1956 data_len = NULL;
1957 par_data = NULL;
1958 if (layout->n_arrays) {
1959 data_len = malloc(sizeof(*data_len) * layout->n_arrays);
1960 if (MPI_dataset->myid == 0) {
1961 for (i = 0; i < layout->n_arrays; i++)
1962 data_len[i] = layout->array_definition[i].dimensions;
1963 }
1964 MPI_Bcast(data_len, layout->n_arrays, MPI_INT64_T, 0, MPI_dataset->comm);
1965 for (i = 0; i < layout->n_arrays; i++) {
1966 type = layout->array_definition[i].type;
1967 size = SDDS_type_size[type - 1];
1968 if (data_len[i]) {
1969 if (type == SDDS_STRING) {
1970 if (MPI_dataset->myid == 0) {
1971 /* it is not easy to broad cast string array, will implement it in the future */
1972 }
1973 } else
1974 MPI_Bcast((char *)SDDS_dataset->array[i].data, data_len[i] * size, MPI_BYTE, 0, MPI_dataset->comm);
1975 }
1976 }
1977 }
1978 /*MPI_dataset->file_offset += SDDS_MPI_GetTitleOffset(MPI_dataset); */
1979 return 1;
1980}
1981
1982/*flag master_read: 1 master processor will read rows; 0: master processor does not read rows.*/
1983/**
1984 * @brief Reads a binary page from an SDDS dataset using MPI parallel I/O.
1985 *
1986 * This function reads a page of data from a binary SDDS file in parallel using MPI. It handles reading the page title,
1987 * distributing the rows among MPI processes, and reading the column or row data depending on the dataset's data mode.
1988 * It also manages error handling and supports read recovery.
1989 *
1990 * @param[in,out] SDDS_dataset Pointer to the SDDS_DATASET structure where the page data will be stored.
1991 *
1992 * @return int32_t Returns the page number on success, 0 on failure, or -1 if end-of-file is reached.
1993 */
1995 int32_t mpi_code, type = 0, retval, master_read;
1996 int64_t i, j, n_rows, prev_rows;
1997 MPI_DATASET *MPI_dataset;
1998 SDDS_FILEBUFFER *fBuffer;
1999 MPI_Status status;
2000 MPI_Offset offset;
2001 long ID_offset;
2002
2003 MPI_dataset = SDDS_dataset->MPI_dataset;
2004 master_read = MPI_dataset->master_read;
2005
2006 if (SDDS_dataset->autoRecovered)
2007 return -1;
2008 if (SDDS_dataset->swapByteOrder) {
2009 return SDDS_MPI_ReadNonNativeBinaryPage(SDDS_dataset);
2010 }
2011 /* static char s[SDDS_MAXLINE]; */
2012 n_rows = 0;
2013 SDDS_SetReadRecoveryMode(SDDS_dataset, 0);
2014 if (MPI_dataset->file_offset >= MPI_dataset->file_size)
2015 return (SDDS_dataset->page_number = -1);
2016 if ((mpi_code = MPI_File_set_view(MPI_dataset->MPI_file, MPI_dataset->file_offset, MPI_BYTE, MPI_BYTE, "native", MPI_INFO_NULL)) != MPI_SUCCESS) {
2017 SDDS_MPI_GOTO_ERROR(stderr, "Unable to set view for read binary page", mpi_code, 0);
2018 SDDS_SetError("Unable to set view for read binary page(1)");
2019 return 0;
2020 }
2021#if defined(MASTER_READTITLE_ONLY)
2022 if (MPI_dataset->myid == 0)
2023#endif
2024 retval = SDDS_MPI_BufferedReadBinaryTitle(SDDS_dataset);
2025#if defined(MASTER_READTITLE_ONLY)
2026 MPI_Bcast(&retval, 1, MPI_INT, 0, MPI_dataset->comm);
2027#endif
2028 /*end of file reached */
2029 if (retval < 0)
2030 return (SDDS_dataset->page_number = -1);
2031 if (retval == 0) {
2032 SDDS_SetError("Unable to read the SDDS title (row number, parameter and/or array) data");
2033 return 0;
2034 }
2035#if defined(MASTER_READTITLE_ONLY)
2036 SDDS_MPI_BroadcastTitleData(SDDS_dataset);
2037#endif
2038 MPI_dataset->file_offset += SDDS_MPI_GetTitleOffset(SDDS_dataset);
2039 if (MPI_dataset->total_rows < 0) {
2040 SDDS_SetError("Unable to read page--negative number of rows (SDDS_MPI_ReadBinaryPage)");
2041 return (0);
2042 }
2043 if (MPI_dataset->total_rows > SDDS_GetRowLimit()) {
2044 /* the number of rows is "unreasonably" large---treat like end-of-file */
2045 return (SDDS_dataset->page_number = -1);
2046 }
2047 prev_rows = 0;
2048 if (master_read) {
2049 n_rows = MPI_dataset->total_rows / MPI_dataset->n_processors;
2050 prev_rows = MPI_dataset->myid * n_rows;
2051 if (MPI_dataset->myid < (ID_offset = MPI_dataset->total_rows % (MPI_dataset->n_processors))) {
2052 n_rows++;
2053 prev_rows += MPI_dataset->myid;
2054 } else
2055 prev_rows += ID_offset;
2056 } else {
2057 if (MPI_dataset->myid == 0)
2058 n_rows = 0;
2059 else {
2060 n_rows = MPI_dataset->total_rows / (MPI_dataset->n_processors - 1);
2061 prev_rows = (MPI_dataset->myid - 1) * n_rows;
2062 if (MPI_dataset->myid <= (ID_offset = MPI_dataset->total_rows % (MPI_dataset->n_processors - 1))) {
2063 n_rows++;
2064 prev_rows += (MPI_dataset->myid - 1);
2065 } else
2066 prev_rows += ID_offset;
2067 }
2068 }
2069 MPI_dataset->start_row = prev_rows; /* This number will be used as the paritlce ID offset */
2070 if (!SDDS_StartPage(SDDS_dataset, 0) || !SDDS_LengthenTable(SDDS_dataset, n_rows)) {
2071 SDDS_SetError("Unable to read page--couldn't start page (SDDS_MPI_ReadBinaryPage)");
2072 return (0);
2073 }
2074 offset = MPI_dataset->file_offset;
2075 fBuffer = &SDDS_dataset->fBuffer;
2076
2077 if (SDDS_dataset->layout.data_mode.column_major) {
2078 /*read by column buffer is not need */
2079 for (i = 0; i < SDDS_dataset->layout.n_columns; i++) {
2080 type = SDDS_dataset->layout.column_definition[i].type;
2081 if (type == SDDS_STRING) {
2082 SDDS_SetError("Can not read string column from SDDS3 (SDDS_MPI_ReadBinaryPage");
2083 return 0;
2084 }
2085 MPI_dataset->file_offset = offset + (MPI_Offset)prev_rows * SDDS_type_size[type - 1];
2086 if ((mpi_code = MPI_File_set_view(MPI_dataset->MPI_file, MPI_dataset->file_offset, MPI_BYTE, MPI_BYTE, "native", MPI_INFO_NULL)) != MPI_SUCCESS) {
2087 SDDS_SetError("Unable to set view for read binary columns");
2088 return 0;
2089 }
2090 if (!MPI_dataset->collective_io) {
2091 if ((mpi_code = MPI_File_read(MPI_dataset->MPI_file, (char *)SDDS_dataset->data[i], n_rows * SDDS_type_size[type - 1], MPI_BYTE, &status)) != MPI_SUCCESS) {
2092 SDDS_SetError("Unable to set view for read binary columns");
2093 return 0;
2094 }
2095 } else {
2096 if ((mpi_code = MPI_File_read_all(MPI_dataset->MPI_file, (char *)SDDS_dataset->data[i], n_rows * SDDS_type_size[type - 1], MPI_BYTE, &status)) != MPI_SUCCESS) {
2097 SDDS_SetError("Unable to set view for read binary columns");
2098 return 0;
2099 }
2100 }
2101 offset += (MPI_Offset)MPI_dataset->total_rows * SDDS_type_size[type - 1];
2102 }
2103 MPI_dataset->n_rows = SDDS_dataset->n_rows = n_rows;
2104 MPI_dataset->file_offset = offset;
2105 } else {
2106 /* read row by row */
2107 if (!fBuffer->buffer) {
2108 fBuffer->bufferSize = SDDS_GetLockedDefaultReadBufferSize();
2109 if (!(fBuffer->buffer = fBuffer->data = SDDS_Malloc(sizeof(char) * (fBuffer->bufferSize + 1)))) {
2110 SDDS_SetError("Unable to do buffered read--allocation failure");
2111 return 0;
2112 }
2113 fBuffer->bytesLeft = 0;
2114 fBuffer->data[0] = 0;
2115 }
2116 if (fBuffer->bytesLeft > 0) {
2117 /* discard the extra data for reading next page */
2118 fBuffer->data[0] = 0;
2119 fBuffer->bytesLeft = 0;
2120 }
2121 MPI_dataset->file_offset += (MPI_Offset)prev_rows * MPI_dataset->column_offset;
2122 if ((mpi_code = MPI_File_set_view(MPI_dataset->MPI_file, MPI_dataset->file_offset, MPI_BYTE, MPI_BYTE, "native", MPI_INFO_NULL)) != MPI_SUCCESS) {
2123 SDDS_MPI_GOTO_ERROR(stderr, "Unable to set view for read binary rows", mpi_code, 0);
2124 SDDS_SetError("Unable to set view for read binary rows");
2125 return 0;
2126 }
2127 if (!master_read || !MPI_dataset->collective_io) {
2128 for (j = 0; j < n_rows; j++) {
2129 if (!SDDS_MPI_ReadBinaryRow(SDDS_dataset, j, 0)) {
2130 SDDS_dataset->n_rows = j;
2131 if (SDDS_dataset->autoRecover) {
2132#if defined(DEBUG)
2133 fprintf(stderr, "Doing auto-read recovery\n");
2134#endif
2135 SDDS_dataset->autoRecovered = 1;
2137 return (SDDS_dataset->page_number = MPI_dataset->n_page);
2138 }
2139 SDDS_SetError("Unable to read page--error reading data row (SDDS_MPI_ReadBinaryPage)");
2140 SDDS_SetReadRecoveryMode(SDDS_dataset, 1);
2141 return (0);
2142 }
2143 }
2144 MPI_dataset->n_rows = SDDS_dataset->n_rows = j;
2145 } else {
2146 MPI_dataset->n_rows = SDDS_dataset->n_rows = n_rows;
2147 if (!SDDS_MPI_CollectiveReadByRow(SDDS_dataset))
2148 return 0;
2149 }
2150 MPI_dataset->file_offset = offset + MPI_dataset->total_rows * MPI_dataset->column_offset;
2151 }
2152 MPI_dataset->n_page++;
2153 return (SDDS_dataset->page_number = MPI_dataset->n_page);
2154}
2155
2156/**
2157 * @brief Reads a non-native binary page from an SDDS dataset using MPI parallel I/O.
2158 *
2159 * This function is a wrapper that calls SDDS_MPI_ReadNonNativePageSparse with mode set to 0,
2160 * facilitating the reading of non-native binary pages.
2161 *
2162 * @param[in,out] SDDS_dataset Pointer to the SDDS_DATASET structure where the page data will be stored.
2163 *
2164 * @return int32_t Returns the page number on success, 0 on failure, or -1 if end-of-file is reached.
2165 */
2167 return SDDS_MPI_ReadNonNativePageSparse(SDDS_dataset, 0);
2168}
2169
2170/**
2171 * @brief Reads a sparse non-native binary page from an SDDS dataset using MPI parallel I/O.
2172 *
2173 * This function reads a page of data from a non-native binary SDDS file in parallel using MPI. The `mode` parameter allows for future expansion.
2174 * It handles reading the title data, broadcasting it to all MPI processes, and reading the column or row data based on the dataset's data mode.
2175 *
2176 * @param[in,out] SDDS_dataset Pointer to the SDDS_DATASET structure where the page data will be stored.
2177 * @param[in] mode Mode flag to support future expansion (currently unused).
2178 *
2179 * @return int32_t Returns the page number on success, 0 on failure, or -1 if end-of-file is reached.
2180 */
2181int32_t SDDS_MPI_ReadNonNativePageSparse(SDDS_DATASET *SDDS_dataset, uint32_t mode)
2182/* the mode argument is to support future expansion */
2183{
2184 int32_t retval;
2185
2186 if (!SDDS_CheckDataset(SDDS_dataset, "SDDS_MPI_ReadNonNativePageSparse"))
2187 return (0);
2188 if (SDDS_dataset->layout.disconnected) {
2189 SDDS_SetError("Can't read page--file is disconnected (SDDS_MPI_ReadNonNativePageSparse)");
2190 return 0;
2191 }
2192
2193 if (SDDS_dataset->original_layout.data_mode.mode == SDDS_ASCII) {
2194 SDDS_SetError("Can not read assii file with parallel io.");
2195 return 0;
2196 } else if (SDDS_dataset->original_layout.data_mode.mode == SDDS_BINARY) {
2197 if ((retval = SDDS_MPI_ReadNonNativeBinaryPage(SDDS_dataset)) < 1) {
2198 return (retval);
2199 }
2200 } else {
2201 SDDS_SetError("Unable to read page--unrecognized data mode (SDDS_MPI_ReadNonNativePageSparse)");
2202 return (0);
2203 }
2204 return (retval);
2205}
2206
2207/**
2208 * @brief Reads a non-native binary page from an SDDS dataset using MPI parallel I/O.
2209 *
2210 * This function reads a page of data from a non-native binary SDDS file in parallel using MPI. It manages reading the title data,
2211 * distributing the rows among MPI processes, and reading the column or row data depending on the dataset's data mode.
2212 * It also handles byte swapping for endianness and error management.
2213 *
2214 * @param[in,out] SDDS_dataset Pointer to the SDDS_DATASET structure where the page data will be stored.
2215 *
2216 * @return int32_t Returns the page number on success, 0 on failure, or -1 if end-of-file is reached.
2217 */
2219 int32_t ID_offset, mpi_code, master_read, type, retval;
2220 int64_t i, j, n_rows, total_rows, prev_rows;
2221 SDDS_FILEBUFFER *fBuffer;
2222 MPI_DATASET *MPI_dataset;
2223 MPI_Offset offset;
2224 MPI_Status status;
2225
2226 MPI_dataset = SDDS_dataset->MPI_dataset;
2227 master_read = MPI_dataset->master_read;
2228 /* static char s[SDDS_MAXLINE]; */
2229 n_rows = 0;
2230 SDDS_SetReadRecoveryMode(SDDS_dataset, 0);
2231 if (MPI_dataset->file_offset >= MPI_dataset->file_size)
2232 return (SDDS_dataset->page_number = -1);
2233
2234 if ((mpi_code = MPI_File_set_view(MPI_dataset->MPI_file, MPI_dataset->file_offset, MPI_BYTE, MPI_BYTE, "native", MPI_INFO_NULL)) != MPI_SUCCESS) {
2235 SDDS_MPI_GOTO_ERROR(stderr, "Unable to set view for read binary page", mpi_code, 0);
2236 SDDS_SetError("Unable to set view for read binary page(1)");
2237 return 0;
2238 }
2239 /* read the number of rows in current page */
2240#if defined(MASTER_READTITLE_ONLY)
2241 if (MPI_dataset->myid == 0)
2242#endif
2243 retval = SDDS_MPI_BufferedReadNonNativeBinaryTitle(SDDS_dataset);
2244#if defined(MASTER_READTITLE_ONLY)
2245 MPI_Bcast(&retval, 1, MPI_INT, 0, MPI_dataset->comm);
2246#endif
2247 /*end of file reached */
2248 if (retval < 0)
2249 return (SDDS_dataset->page_number = -1);
2250 if (retval == 0) {
2251 SDDS_SetError("Unable to read the SDDS title (row number, parameter and/or array) data");
2252 return 0;
2253 }
2254#if defined(MASTER_READTITLE_ONLY)
2255 SDDS_MPI_BroadcastTitleData(SDDS_dataset);
2256#endif
2257 MPI_dataset->file_offset += SDDS_MPI_GetTitleOffset(SDDS_dataset);
2258 if (MPI_dataset->total_rows < 0) {
2259 SDDS_SetError("Unable to read page--negative number of rows (SDDS_MPI_ReadBinaryPage)");
2260 return (0);
2261 }
2262 if (MPI_dataset->total_rows > SDDS_GetRowLimit()) {
2263 /* the number of rows is "unreasonably" large---treat like end-of-file */
2264 return (SDDS_dataset->page_number = -1);
2265 }
2266 total_rows = MPI_dataset->total_rows;
2267 prev_rows = 0;
2268 if (master_read) {
2269 n_rows = total_rows / MPI_dataset->n_processors;
2270 prev_rows = MPI_dataset->myid * n_rows;
2271 if (MPI_dataset->myid < (ID_offset = total_rows % (MPI_dataset->n_processors))) {
2272 n_rows++;
2273 prev_rows += MPI_dataset->myid;
2274 } else
2275 prev_rows += ID_offset;
2276 } else {
2277 if (MPI_dataset->myid == 0)
2278 n_rows = 0;
2279 else {
2280 n_rows = total_rows / (MPI_dataset->n_processors - 1);
2281 prev_rows = (MPI_dataset->myid - 1) * n_rows;
2282 if (MPI_dataset->myid <= (ID_offset = total_rows % (MPI_dataset->n_processors - 1))) {
2283 n_rows++;
2284 prev_rows += (MPI_dataset->myid - 1);
2285 } else
2286 prev_rows += ID_offset;
2287 }
2288 }
2289 MPI_dataset->start_row = prev_rows; /* This number will be used as the paritlce ID offset */
2290 if (!SDDS_StartPage(SDDS_dataset, 0) || !SDDS_LengthenTable(SDDS_dataset, n_rows)) {
2291 SDDS_SetError("Unable to read page--couldn't start page (SDDS_MPI_ReadNonNativeBinaryPage)");
2292 return (0);
2293 }
2294
2295 offset = MPI_dataset->file_offset;
2296 fBuffer = &SDDS_dataset->fBuffer;
2297 if (SDDS_dataset->layout.data_mode.column_major) {
2298 /*read by column buffer is not need */
2299 for (i = 0; i < SDDS_dataset->layout.n_columns; i++) {
2300 type = SDDS_dataset->layout.column_definition[i].type;
2301 if (type == SDDS_STRING) {
2302 SDDS_SetError("Can not read string column from SDDS3 (SDDS_MPI_ReadBinaryPage");
2303 return 0;
2304 }
2305 MPI_dataset->file_offset = offset + (MPI_Offset)prev_rows * SDDS_type_size[type - 1];
2306 if ((mpi_code = MPI_File_set_view(MPI_dataset->MPI_file, MPI_dataset->file_offset, MPI_BYTE, MPI_BYTE, "native", MPI_INFO_NULL)) != MPI_SUCCESS) {
2307 SDDS_SetError("Unable to set view for read binary columns");
2308 return 0;
2309 }
2310 if (!MPI_dataset->collective_io) {
2311 if ((mpi_code = MPI_File_read(MPI_dataset->MPI_file, (char *)SDDS_dataset->data[i], n_rows * SDDS_type_size[type - 1], MPI_BYTE, &status)) != MPI_SUCCESS) {
2312 SDDS_SetError("Unable to set view for read binary columns");
2313 return 0;
2314 }
2315 } else {
2316 if ((mpi_code = MPI_File_read_all(MPI_dataset->MPI_file, (char *)SDDS_dataset->data[i], n_rows * SDDS_type_size[type - 1], MPI_BYTE, &status)) != MPI_SUCCESS) {
2317 SDDS_SetError("Unable to set view for read binary columns");
2318 return 0;
2319 }
2320 }
2321 offset += (MPI_Offset)MPI_dataset->total_rows * SDDS_type_size[type - 1];
2322 }
2323 MPI_dataset->n_rows = SDDS_dataset->n_rows = n_rows;
2324 MPI_dataset->file_offset = offset;
2325 } else {
2326 /* read row by row */
2327 if (!fBuffer->buffer) {
2328 fBuffer->bufferSize = SDDS_GetLockedDefaultReadBufferSize();
2329 if (!(fBuffer->buffer = fBuffer->data = SDDS_Malloc(sizeof(char) * (fBuffer->bufferSize + 1)))) {
2330 SDDS_SetError("Unable to do buffered read--allocation failure");
2331 return 0;
2332 }
2333 fBuffer->bytesLeft = 0;
2334 fBuffer->data[0] = 0;
2335 }
2336 if (fBuffer->bytesLeft > 0) {
2337 /* discard the extra data for reading next page */
2338 fBuffer->data[0] = 0;
2339 fBuffer->bytesLeft = 0;
2340 }
2341 MPI_dataset->file_offset += (MPI_Offset)prev_rows * MPI_dataset->column_offset;
2342 if ((mpi_code = MPI_File_set_view(MPI_dataset->MPI_file, MPI_dataset->file_offset, MPI_BYTE, MPI_BYTE, "native", MPI_INFO_NULL)) != MPI_SUCCESS) {
2343 SDDS_MPI_GOTO_ERROR(stderr, "Unable to set view for read binary rows", mpi_code, 0);
2344 SDDS_SetError("Unable to set view for read binary rows");
2345 return 0;
2346 }
2347 if (!MPI_dataset->collective_io || !master_read) {
2348 for (j = 0; j < n_rows; j++) {
2349 if (!SDDS_MPI_ReadBinaryRow(SDDS_dataset, j, 0)) {
2350 SDDS_dataset->n_rows = j - 1;
2351 if (SDDS_dataset->autoRecover) {
2353 SDDS_SwapEndsColumnData(SDDS_dataset);
2354 return (SDDS_dataset->page_number = MPI_dataset->n_page);
2355 }
2356 SDDS_SetError("Unable to read page--error reading data row (SDDS_MPI_ReadNonNativeBinaryPage)");
2357 SDDS_SetReadRecoveryMode(SDDS_dataset, 1);
2358 return (0);
2359 }
2360 }
2361 SDDS_dataset->n_rows = j;
2362 } else {
2363 MPI_dataset->n_rows = SDDS_dataset->n_rows = n_rows;
2364 if (!SDDS_MPI_CollectiveReadByRow(SDDS_dataset))
2365 return 0;
2366 }
2367 MPI_dataset->file_offset = offset + MPI_dataset->total_rows * MPI_dataset->column_offset;
2368 }
2369 SDDS_SwapEndsColumnData(SDDS_dataset);
2370 MPI_dataset->n_page++;
2371 MPI_Barrier(MPI_dataset->comm);
2372 return (SDDS_dataset->page_number = MPI_dataset->n_page);
2373}
2374
2375/**
2376 * @brief Buffers and reads the non-native binary title data from an SDDS dataset using MPI.
2377 *
2378 * This function initializes and manages a buffered read for the title section of a non-native binary SDDS dataset.
2379 * It reads the total number of rows, parameters, and arrays from the binary file buffer. The function handles
2380 * memory allocation for the buffer, byte swapping for endianness, and initializes the SDDS page structure.
2381 *
2382 * @param[in,out] SDDS_dataset Pointer to the `SDDS_DATASET` structure where the title data will be stored.
2383 *
2384 * @return int32_t Returns `1` on successful read, `0` on failure, and `-1` if the end of the file is reached.
2385 */
2387 SDDS_FILEBUFFER *fBuffer = NULL;
2388 MPI_DATASET *MPI_dataset = NULL;
2389 int32_t ret_val;
2390 int32_t total_rows;
2391
2392 MPI_dataset = SDDS_dataset->MPI_dataset;
2393 fBuffer = &(SDDS_dataset->titleBuffer);
2394 if (!fBuffer->buffer) {
2395 fBuffer->bufferSize = SDDS_GetLockedDefaultTitleBufferSize();
2396 if (!(fBuffer->buffer = fBuffer->data = SDDS_Malloc(sizeof(char) * (fBuffer->bufferSize + 1)))) {
2397 SDDS_SetError("Unable to do buffered read--allocation failure(SDDS_MPI_ReadNonNativeBinaryTitle)");
2398 return 0;
2399 }
2400 fBuffer->bytesLeft = 0;
2401 }
2402 if (fBuffer->bytesLeft > 0) {
2403 /* discard the extra data for reading next page */
2404 fBuffer->data[0] = 0;
2405 fBuffer->bytesLeft = 0;
2406 }
2407 if ((ret_val = SDDS_MPI_BufferedRead((void *)&(total_rows), sizeof(int32_t), SDDS_dataset, fBuffer)) < 0)
2408 return -1;
2409 SDDS_SwapLong(&(total_rows));
2410 if (total_rows == INT32_MIN) {
2411 if ((ret_val = SDDS_MPI_BufferedRead((void *)&(MPI_dataset->total_rows), sizeof(int64_t), SDDS_dataset, fBuffer)) < 0)
2412 return -1;
2413 } else {
2414 MPI_dataset->total_rows = total_rows;
2415 }
2416 if (!ret_val)
2417 return 0;
2418 if (!SDDS_StartPage(SDDS_dataset, 0)) {
2419 SDDS_SetError("Unable to read page--couldn't start page (SDDS_MPI_BufferedReadNonNativeBinaryTitle)");
2420 return (0);
2421 }
2422 /*read parameters */
2423 if (!SDDS_MPI_ReadNonNativeBinaryParameters(SDDS_dataset, fBuffer)) {
2424 SDDS_SetError("Unable to read page--parameter reading error (SDDS_MPI_BufferedNonNativeReadTitle)");
2425 return (0);
2426 }
2427 /*read arrays */
2428 if (!SDDS_MPI_ReadNonNativeBinaryArrays(SDDS_dataset, fBuffer)) {
2429 SDDS_SetError("Unable to read page--array reading error (SDDS_MPI_BufferedNonNativeReadTitle)");
2430 return (0);
2431 }
2432
2433 return 1;
2434}
2435
2436/*obtain the offset of n_rows, parameters and arrays which are written by master processor */
2437/**
2438 * @brief Calculates the byte offset for the title section in a non-native binary SDDS dataset.
2439 *
2440 * This function computes the total byte offset required to read the number of rows, parameters, and arrays
2441 * defined in the SDDS dataset. It accounts for different data types, including strings, and variable-length
2442 * parameters and arrays. The calculated offset is used to position the MPI file view correctly for reading.
2443 *
2444 * @param[in] SDDS_dataset Pointer to the `SDDS_DATASET` structure containing the dataset layout and data.
2445 *
2446 * @return MPI_Offset The total byte offset of the title section in the binary file.
2447 */
2448MPI_Offset SDDS_MPI_GetTitleOffset(SDDS_DATASET *SDDS_dataset) {
2449 int64_t i, j;
2450 MPI_Offset offset = 0;
2451 SDDS_LAYOUT *layout;
2452
2453 layout = &(SDDS_dataset->layout);
2454 offset += sizeof(int32_t);
2455 if (SDDS_dataset->n_rows > INT32_MAX) {
2456 offset += sizeof(int64_t);
2457 }
2458 for (i = 0; i < layout->n_parameters; i++) {
2459 if (layout->parameter_definition[i].fixed_value)
2460 continue;
2461 if (layout->parameter_definition[i].type == SDDS_STRING) {
2462 if (*(char **)SDDS_dataset->parameter[i])
2463 offset += sizeof(int32_t) + sizeof(char) * strlen(*(char **)SDDS_dataset->parameter[i]);
2464 else
2465 offset += sizeof(int32_t); /*write length 0 for NULL string */
2466 } else {
2467 offset += SDDS_type_size[layout->parameter_definition[i].type - 1];
2468 }
2469 }
2470 for (i = 0; i < layout->n_arrays; i++) {
2471 if (!(SDDS_dataset->array[i].dimension)) {
2472 offset += layout->array_definition[i].dimensions * sizeof(int32_t);
2473 continue;
2474 }
2475 offset += sizeof(*(SDDS_dataset->array)[i].dimension) * layout->array_definition[i].dimensions;
2476 if (layout->array_definition[i].type == SDDS_STRING) {
2477 for (j = 0; j < SDDS_dataset->array[i].elements; j++) {
2478 if (((char **)SDDS_dataset->array[i].data)[j])
2479 offset += sizeof(int32_t) + sizeof(char) * strlen(((char **)SDDS_dataset->array[i].data)[j]);
2480 else
2481 offset += sizeof(int32_t);
2482 }
2483 } else {
2484 offset += SDDS_type_size[layout->array_definition[i].type - 1] * SDDS_dataset->array[i].elements;
2485 }
2486 }
2487 return offset;
2488}
2489
2490/*use a small size of buffer to read the total_rows, parameters and arrays of each page */
2491/**
2492 * @brief Buffers and reads the binary title data from an SDDS dataset using MPI.
2493 *
2494 * This function initializes and manages a buffered read for the title section of a native binary SDDS dataset.
2495 * It reads the total number of rows, parameters, and arrays from the binary file buffer. The function handles
2496 * memory allocation for the buffer and initializes the SDDS page structure.
2497 *
2498 * @param[in,out] SDDS_dataset Pointer to the `SDDS_DATASET` structure where the title data will be stored.
2499 *
2500 * @return int32_t Returns `1` on successful read, `0` on failure, and `-1` if the end of the file is reached.
2501 */
2503 SDDS_FILEBUFFER *fBuffer = NULL;
2504 MPI_DATASET *MPI_dataset = NULL;
2505 int32_t ret_val;
2506 int32_t total_rows;
2507
2508 MPI_dataset = SDDS_dataset->MPI_dataset;
2509 fBuffer = &(SDDS_dataset->titleBuffer);
2510 if (!fBuffer->buffer) {
2511 fBuffer->bufferSize = SDDS_GetLockedDefaultTitleBufferSize();
2512 if (!(fBuffer->buffer = fBuffer->data = SDDS_Malloc(sizeof(char) * (fBuffer->bufferSize + 1)))) {
2513 SDDS_SetError("Unable to do buffered read--allocation failure(SDDS_MPI_ReadBinaryTitle)");
2514 return 0;
2515 }
2516 fBuffer->bytesLeft = 0;
2517 }
2518 if (fBuffer->bytesLeft > 0) {
2519 /* discard the extra data for reading next page */
2520 fBuffer->data[0] = 0;
2521 fBuffer->bytesLeft = 0;
2522 }
2523 if ((ret_val = SDDS_MPI_BufferedRead((void *)&(total_rows), sizeof(int32_t), SDDS_dataset, fBuffer)) < 0)
2524 return -1;
2525 if (total_rows == INT32_MIN) {
2526 if ((ret_val = SDDS_MPI_BufferedRead((void *)&(MPI_dataset->total_rows), sizeof(int64_t), SDDS_dataset, fBuffer)) < 0)
2527 return -1;
2528 } else {
2529 MPI_dataset->total_rows = total_rows;
2530 }
2531 if (!ret_val)
2532 return 0;
2533 if (!SDDS_StartPage(SDDS_dataset, 0)) {
2534 SDDS_SetError("Unable to read page--couldn't start page (SDDS_MPI_BufferedReadBinaryTitle)");
2535 return (0);
2536 }
2537 /*read parameters */
2538 if (!SDDS_MPI_ReadBinaryParameters(SDDS_dataset, fBuffer)) {
2539 SDDS_SetError("Unable to read page--parameter reading error (SDDS_MPI_BufferedReadTitle)");
2540 return (0);
2541 }
2542 /*read arrays */
2543 if (!SDDS_MPI_ReadBinaryArrays(SDDS_dataset, fBuffer)) {
2544 SDDS_SetError("Unable to read page--array reading error (SDDS_MPI_BufferedReadTitle)");
2545 return (0);
2546 }
2547
2548 return 1;
2549}
2550
2551/**
2552 * @brief Writes SDDS dataset rows collectively by row using MPI parallel I/O.
2553 *
2554 * This function performs a collective write operation where each MPI process writes its assigned rows of the SDDS dataset.
2555 * It handles buffering of row data, ensures synchronization among MPI processes, and manages error handling.
2556 * The function supports only binary string types for non-string data and flushes the buffer upon completion.
2557 *
2558 * @param[in,out] SDDS_dataset Pointer to the `SDDS_DATASET` structure containing the data to be written.
2559 *
2560 * @return int32_t Returns `1` on successful write, `0` on failure.
2561 */
2563 MPI_DATASET *MPI_dataset;
2564 SDDS_LAYOUT *layout;
2565 int32_t mpi_code, type, size;
2566 int64_t i, j, n_rows, min_rows, writeBytes;
2567 SDDS_FILEBUFFER *fBuffer;
2568
2569#if MPI_DEBUG
2570 logDebug("SDDS_MPI_CollectiveWriteByRow", SDDS_dataset);
2571#endif
2572
2573 MPI_dataset = SDDS_dataset->MPI_dataset;
2574 layout = &(SDDS_dataset->layout);
2575 fBuffer = &(SDDS_dataset->fBuffer);
2576 n_rows = SDDS_dataset->n_rows;
2577 MPI_Allreduce(&n_rows, &min_rows, 1, MPI_INT64_T, MPI_MIN, MPI_dataset->comm);
2578 for (i = 0; i < min_rows; i++) {
2579 for (j = 0; j < layout->n_columns; j++) {
2580 type = layout->column_definition[j].type;
2581 size = SDDS_type_size[type - 1];
2582 if (type == SDDS_STRING) {
2583 SDDS_SetError("Can not write binary string in collective io.");
2584 return 0;
2585 }
2586 if (!SDDS_MPI_BufferedWriteAll((char *)SDDS_dataset->data[j] + i * size, size, SDDS_dataset))
2587 return 0;
2588 }
2589 }
2590
2591 if ((writeBytes = fBuffer->bufferSize - fBuffer->bytesLeft)) {
2592 if (writeBytes < 0) {
2593 SDDS_SetError("Unable to flush buffer: negative byte count (SDDS_FlushBuffer).");
2594 return 0;
2595 }
2596 if ((mpi_code = MPI_File_write_all(MPI_dataset->MPI_file, fBuffer->buffer, writeBytes, MPI_BYTE, MPI_STATUS_IGNORE)) != MPI_SUCCESS) {
2597 SDDS_MPI_GOTO_ERROR(stderr, "SDDS_MPI_FlushBuffer(MPI_File_write_at failed)", mpi_code, 0);
2598 return 0;
2599 }
2600 fBuffer->bytesLeft = fBuffer->bufferSize;
2601 fBuffer->data = fBuffer->buffer;
2602 }
2603
2604 for (i = min_rows; i < n_rows; i++)
2605 if (!SDDS_MPI_WriteBinaryRow(SDDS_dataset, i))
2606 return 0;
2607 if (!SDDS_MPI_FlushBuffer(SDDS_dataset))
2608 return 0;
2609 return 1;
2610}
2611
2612/**
2613 * @brief Writes non-native binary SDDS dataset rows collectively by row using MPI parallel I/O.
2614 *
2615 * This function performs a collective write operation for non-native binary SDDS datasets, where each MPI process writes
2616 * its assigned rows. It handles buffering of row data, ensures synchronization among MPI processes, and manages error handling.
2617 * The function supports only binary string types for non-string data and flushes the buffer upon completion.
2618 *
2619 * @param[in,out] SDDS_dataset Pointer to the `SDDS_DATASET` structure containing the data to be written.
2620 *
2621 * @return int32_t Returns `1` on successful write, `0` on failure.
2622 */
2624 MPI_DATASET *MPI_dataset;
2625 SDDS_LAYOUT *layout;
2626 int32_t mpi_code, type, size;
2627 int64_t i, j, n_rows, min_rows, writeBytes;
2628 SDDS_FILEBUFFER *fBuffer;
2629
2630#if MPI_DEBUG
2631 logDebug("SDDS_MPI_CollectiveWriteNonNativeByRow", SDDS_dataset);
2632#endif
2633
2634 MPI_dataset = SDDS_dataset->MPI_dataset;
2635 layout = &(SDDS_dataset->layout);
2636 fBuffer = &(SDDS_dataset->fBuffer);
2637 n_rows = SDDS_dataset->n_rows;
2638 MPI_Allreduce(&n_rows, &min_rows, 1, MPI_INT64_T, MPI_MIN, MPI_dataset->comm);
2639 for (i = 0; i < min_rows; i++) {
2640 for (j = 0; j < layout->n_columns; j++) {
2641 type = layout->column_definition[j].type;
2642 size = SDDS_type_size[type - 1];
2643 if (type == SDDS_STRING) {
2644 SDDS_SetError("Can not write binary string in collective io.");
2645 return 0;
2646 }
2647 if (!SDDS_MPI_BufferedWriteAll((char *)SDDS_dataset->data[j] + i * size, size, SDDS_dataset))
2648 return 0;
2649 }
2650 }
2651
2652 if ((writeBytes = fBuffer->bufferSize - fBuffer->bytesLeft)) {
2653 if (writeBytes < 0) {
2654 SDDS_SetError("Unable to flush buffer: negative byte count (SDDS_FlushBuffer).");
2655 return 0;
2656 }
2657 if ((mpi_code = MPI_File_write_all(MPI_dataset->MPI_file, fBuffer->buffer, writeBytes, MPI_BYTE, MPI_STATUS_IGNORE)) != MPI_SUCCESS) {
2658 SDDS_MPI_GOTO_ERROR(stderr, "SDDS_MPI_FlushBuffer(MPI_File_write_at failed)", mpi_code, 0);
2659 return 0;
2660 }
2661 fBuffer->bytesLeft = fBuffer->bufferSize;
2662 fBuffer->data = fBuffer->buffer;
2663 }
2664
2665 for (i = min_rows; i < n_rows; i++)
2666 if (!SDDS_MPI_WriteNonNativeBinaryRow(SDDS_dataset, i))
2667 return 0;
2668 if (!SDDS_MPI_FlushBuffer(SDDS_dataset))
2669 return 0;
2670 return 1;
2671}
2672
2673/**
2674 * @brief Reads SDDS dataset rows collectively by row using MPI parallel I/O.
2675 *
2676 * This function performs a collective read operation where each MPI process reads its assigned rows of the SDDS dataset.
2677 * It handles buffering of row data, ensures synchronization among MPI processes, and manages error handling.
2678 * The function supports only binary string types for non-string data and flushes the buffer upon completion.
2679 *
2680 * @param[in,out] SDDS_dataset Pointer to the `SDDS_DATASET` structure where the data will be stored.
2681 *
2682 * @return int32_t Returns `1` on successful read, `0` on failure.
2683 */
2685
2686 SDDS_FILEBUFFER *fBuffer;
2687 MPI_DATASET *MPI_dataset;
2688 int32_t type, size;
2689 int64_t min_rows, i, j;
2690 SDDS_LAYOUT *layout;
2691
2692 MPI_dataset = SDDS_dataset->MPI_dataset;
2693 fBuffer = &(SDDS_dataset->fBuffer);
2694 layout = &(SDDS_dataset->layout);
2695
2696 if (!MPI_dataset->master_read) {
2697 SDDS_SetError("Cannot read row with collective io when master is not reading the data.");
2698 return 0;
2699 }
2700 min_rows = MPI_dataset->total_rows / MPI_dataset->n_processors;
2701 for (i = 0; i < min_rows; i++) {
2702 for (j = 0; j < layout->n_columns; j++) {
2703 type = layout->column_definition[j].type;
2704 size = SDDS_type_size[type - 1];
2705 if (type == SDDS_STRING) {
2706 SDDS_SetError("Can not write binary string in collective io.");
2707 return 0;
2708 }
2709 if (!SDDS_MPI_BufferedReadAll((char *)SDDS_dataset->data[j] + i * size, size, SDDS_dataset, fBuffer))
2710 return 0;
2711 }
2712 }
2713 for (i = min_rows; i < MPI_dataset->n_rows; i++)
2714 if (!SDDS_MPI_ReadBinaryRow(SDDS_dataset, i, 0))
2715 return 0;
2716
2717 return 1;
2718}
SDDS (Self Describing Data Set) Data Types Definitions and Function Prototypes.
int32_t SDDS_MPI_WriteBinaryParameters(SDDS_DATASET *SDDS_dataset)
Write binary parameters of an SDDS dataset using MPI.
int32_t SDDS_MPI_ReadNonNativeBinaryRow(SDDS_DATASET *SDDS_dataset, int64_t row, int32_t skip)
Reads a single non-native binary row from a binary file buffer into the SDDS dataset using MPI.
int32_t SDDS_MPI_BufferedReadNonNativeBinaryTitle(SDDS_DATASET *SDDS_dataset)
Buffers and reads the non-native binary title data from an SDDS dataset using MPI.
int32_t SDDS_MPI_WriteBinaryRow(SDDS_DATASET *SDDS_dataset, int64_t row)
Write a binary row to an SDDS dataset using MPI.
int32_t SDDS_MPI_CollectiveWriteNonNativeByRow(SDDS_DATASET *SDDS_dataset)
Writes non-native binary SDDS dataset rows collectively by row using MPI parallel I/O.
char * SDDS_MPI_ReadBinaryString(SDDS_DATASET *SDDS_dataset, SDDS_FILEBUFFER *fBuffer, int32_t skip)
Read a binary string from the SDDS dataset using MPI.
int32_t SDDS_MPI_FlushBuffer(SDDS_DATASET *SDDS_dataset)
Flush the buffer by writing any remaining data to the MPI file.
int32_t SDDS_MPI_WriteBinaryString(SDDS_DATASET *SDDS_dataset, char *string)
Write a binary string to an SDDS dataset using MPI.
int32_t SDDS_MPI_WriteContinuousBinaryPage(SDDS_DATASET *SDDS_dataset)
Write a continuous binary page of the SDDS dataset using MPI.
int32_t SDDS_MPI_BufferedReadBinaryTitle(SDDS_DATASET *SDDS_dataset)
Buffers and reads the binary title data from an SDDS dataset using MPI.
void SDDS_StringTuncated(void)
Increment the truncated strings counter.
void SDDS_MPI_SetFileSync(short value)
Set the file synchronization flag.
int32_t SDDS_SetDefaultStringLength(int32_t newValue)
Set the default string length for SDDS.
int32_t SDDS_MPI_ReadNonNativePage(SDDS_DATASET *SDDS_dataset)
Reads a non-native binary page from an SDDS dataset using MPI parallel I/O.
int32_t SDDS_MPI_ReadBinaryParameters(SDDS_DATASET *SDDS_dataset, SDDS_FILEBUFFER *fBuffer)
Read binary parameters from the SDDS dataset using MPI.
int32_t SDDS_MPI_WriteNonNativeBinaryRow(SDDS_DATASET *SDDS_dataset, int64_t row)
Write a non-native binary row to an SDDS dataset using MPI.
int32_t SDDS_MPI_BufferedRead(void *target, int64_t targetSize, SDDS_DATASET *SDDS_dataset, SDDS_FILEBUFFER *fBuffer)
Buffered read from an SDDS dataset using MPI.
MPI_Offset SDDS_MPI_GetTitleOffset(SDDS_DATASET *SDDS_dataset)
Calculates the byte offset for the title section in a non-native binary SDDS dataset.
int32_t SDDS_MPI_CollectiveReadByRow(SDDS_DATASET *SDDS_dataset)
Reads SDDS dataset rows collectively by row using MPI parallel I/O.
int64_t SDDS_MPI_CountRowsOfInterest(SDDS_DATASET *SDDS_dataset, int64_t start_row, int64_t end_row)
Count the number of rows marked as "of interest" within a specified range.
int32_t SDDS_SetDefaultWriteBufferSize(int32_t newSize)
Set the default write buffer size for SDDS.
MPI_Offset SDDS_MPI_Get_Column_Size(SDDS_DATASET *SDDS_dataset)
Get the total size of all columns in an SDDS dataset.
int32_t SDDS_CheckStringTruncated(void)
Check the number of truncated strings.
int64_t SDDS_MPI_GetTotalRows(SDDS_DATASET *SDDS_dataset)
Get the total number of rows across all MPI processes.
int32_t SDDS_MPI_WriteBinaryPage(SDDS_DATASET *SDDS_dataset)
Write an SDDS binary page using MPI.
int32_t SDDS_MPI_WriteNonNativeBinaryString(SDDS_DATASET *SDDS_dataset, char *string)
Write a non-native binary string to an SDDS dataset using MPI.
int32_t SDDS_MPI_ReadNonNativeBinaryParameters(SDDS_DATASET *SDDS_dataset, SDDS_FILEBUFFER *fBuffer)
Read non-native binary parameters from the SDDS dataset using MPI.
int32_t SDDS_MPI_WriteBinaryArrays(SDDS_DATASET *SDDS_dataset)
Write binary arrays of an SDDS dataset using MPI.
int32_t SDDS_MPI_WriteNonNativeBinaryArrays(SDDS_DATASET *SDDS_dataset)
Write non-native binary arrays of an SDDS dataset using MPI.
int32_t SDDS_MPI_BufferedWrite(void *target, int64_t targetSize, SDDS_DATASET *SDDS_dataset)
Buffered write to an SDDS dataset using MPI.
int32_t SDDS_MPI_ReadBinaryArrays(SDDS_DATASET *SDDS_dataset, SDDS_FILEBUFFER *fBuffer)
Read binary arrays from the SDDS dataset using MPI.
int32_t SDDS_MPI_WriteNonNativeBinaryParameters(SDDS_DATASET *SDDS_dataset)
Write non-native binary parameters of an SDDS dataset using MPI.
int32_t SDDS_MPI_ReadBinaryPage(SDDS_DATASET *SDDS_dataset)
Reads a binary page from an SDDS dataset using MPI parallel I/O.
int32_t SDDS_MPI_BufferedWriteAll(void *target, int64_t targetSize, SDDS_DATASET *SDDS_dataset)
Buffered write all to an SDDS dataset using MPI.
int32_t SDDS_SetDefaultReadBufferSize(int32_t newSize)
Set the default read buffer size for SDDS.
int32_t SDDS_MPI_BroadcastTitleData(SDDS_DATASET *SDDS_dataset)
Broadcasts the title data (parameters and arrays) of the SDDS dataset to all MPI processes.
int32_t SDDS_MPI_ReadBinaryRow(SDDS_DATASET *SDDS_dataset, int64_t row, int32_t skip)
Read a binary row from the SDDS dataset using MPI.
int32_t SDDS_MPI_BufferedReadAll(void *target, int64_t targetSize, SDDS_DATASET *SDDS_dataset, SDDS_FILEBUFFER *fBuffer)
Buffered read all from an SDDS dataset using MPI.
int32_t SDDS_MPI_ReadNonNativeBinaryArrays(SDDS_DATASET *SDDS_dataset, SDDS_FILEBUFFER *fBuffer)
Reads non-native binary arrays from a binary file buffer into the SDDS dataset using MPI.
int32_t SDDS_MPI_CollectiveWriteByRow(SDDS_DATASET *SDDS_dataset)
Writes SDDS dataset rows collectively by row using MPI parallel I/O.
int32_t SDDS_SetDefaultTitleBufferSize(int32_t newSize)
Set the default title buffer size for SDDS.
void SDDS_MPI_SetWriteKludgeUsleep(long value)
Set the write kludge usleep duration.
int32_t SDDS_MPI_ReadNonNativePageSparse(SDDS_DATASET *SDDS_dataset, uint32_t mode)
Reads a sparse non-native binary page from an SDDS dataset using MPI parallel I/O.
int32_t SDDS_MPI_WriteNonNativeBinaryPage(SDDS_DATASET *SDDS_dataset)
Write a non-native binary page of the SDDS dataset using MPI.
int32_t SDDS_MPI_ReadNonNativeBinaryPage(SDDS_DATASET *SDDS_dataset)
Reads a non-native binary page from an SDDS dataset using MPI parallel I/O.
char * SDDS_MPI_ReadNonNativeBinaryString(SDDS_DATASET *SDDS_dataset, SDDS_FILEBUFFER *fBuffer, int32_t skip)
Read a non-native binary string from the SDDS dataset using MPI.
int32_t SDDS_ScanData(char *string, int32_t type, int32_t field_length, void *data, int64_t index, int32_t is_parameter)
Scans a string and saves the parsed value into a data pointer according to the specified data type.
int32_t SDDS_SwapEndsColumnData(SDDS_DATASET *SDDSin)
Swaps the endianness of the column data in an SDDS dataset.
void SDDS_SwapLong64(int64_t *data)
Swaps the endianness of a 64-bit integer.
void SDDS_SetReadRecoveryMode(SDDS_DATASET *SDDS_dataset, int32_t mode)
Sets the read recovery mode for an SDDS dataset.
int32_t SDDS_SwapEndsArrayData(SDDS_DATASET *SDDSin)
Swaps the endianness of the array data in an SDDS dataset.
int32_t SDDS_SwapEndsParameterData(SDDS_DATASET *SDDSin)
Swaps the endianness of the parameter data in an SDDS dataset.
void SDDS_SwapLong(int32_t *data)
Swaps the endianness of a 32-bit integer.
int32_t SDDS_type_size[SDDS_NUM_TYPES]
Array of sizes for each supported data type.
Definition SDDS_data.c:62
int32_t SDDS_LengthenTable(SDDS_DATASET *SDDS_dataset, int64_t n_additional_rows)
int32_t SDDS_StartPage(SDDS_DATASET *SDDS_dataset, int64_t expected_n_rows)
int64_t SDDS_CountRowsOfInterest(SDDS_DATASET *SDDS_dataset)
Counts the number of rows marked as "of interest" in the current data table.
int64_t SDDS_GetRowLimit()
void SDDS_SetError(char *error_text)
Records an error message in the SDDS error stack.
Definition SDDS_utils.c:421
int32_t SDDS_FreeArrayDefinition(ARRAY_DEFINITION *source)
Frees memory allocated for an array definition.
int32_t SDDS_CheckDataset(SDDS_DATASET *SDDS_dataset, const char *caller)
Validates the SDDS dataset pointer.
Definition SDDS_utils.c:618
void * SDDS_Malloc(size_t size)
Allocates memory of a specified size.
Definition SDDS_utils.c:705
void SDDS_ClearErrors()
Clears all recorded error messages from the SDDS error stack.
Definition SDDS_utils.c:354
ARRAY_DEFINITION * SDDS_CopyArrayDefinition(ARRAY_DEFINITION **target, ARRAY_DEFINITION *source)
Creates a copy of an array definition.
int32_t SDDS_IsBigEndianMachine()
Determines whether the current machine uses big-endian byte ordering.
void * SDDS_Realloc(void *old_ptr, size_t new_size)
Reallocates memory to a new size.
Definition SDDS_utils.c:743
void SDDS_MPI_GOTO_ERROR(FILE *fp, char *str, int32_t mpierr, int32_t exit_code)
Handles MPI errors by printing an error message and optionally exiting.
#define SDDS_STRING
Identifier for the string data type.
Definition SDDStypes.h:85
void usleepSystemIndependent(long usec)
Sleep for a given number of microseconds, system-independently.