1 /* -*- Mode: C; c-basic-offset:4 ; -*- */
2 /*
3  *
4  *   Copyright (C) 1997 University of Chicago.
5  *   See COPYRIGHT notice in top-level directory.
6  */
7 
8 #include "ad_piofs.h"
9 #include "adio_extern.h"
10 
ADIOI_PIOFS_WriteContig(ADIO_File fd,void * buf,int count,MPI_Datatype datatype,int file_ptr_type,ADIO_Offset offset,ADIO_Status * status,int * error_code)11 void ADIOI_PIOFS_WriteContig(ADIO_File fd, void *buf, int count,
12                      MPI_Datatype datatype, int file_ptr_type,
13 		     ADIO_Offset offset, ADIO_Status *status, int *error_code)
14 {
15     int err=-1, datatype_size, len;
16 #ifndef PRINT_ERR_MSG
17     static char myname[] = "ADIOI_PIOFS_WRITECONTIG";
18 #endif
19 
20     MPI_Type_size(datatype, &datatype_size);
21     len = datatype_size * count;
22 
23     if (file_ptr_type == ADIO_EXPLICIT_OFFSET) {
24 	if (fd->fp_sys_posn != offset) {
25 	    llseek(fd->fd_sys, offset, SEEK_SET);
26 	}
27 	err = write(fd->fd_sys, buf, len);
28 	fd->fp_sys_posn = offset + err;
29 	/* individual file pointer not updated */
30     }
31     else { /* write from curr. location of ind. file pointer */
32 	if (fd->fp_sys_posn != fd->fp_ind) {
33 	    llseek(fd->fd_sys, fd->fp_ind, SEEK_SET);
34 	}
35 	err = write(fd->fd_sys, buf, len);
36 	fd->fp_ind += err;
37 	fd->fp_sys_posn = fd->fp_ind;
38     }
39 
40 #ifdef HAVE_STATUS_SET_BYTES
41     if (err != -1) MPIR_Status_set_bytes(status, datatype, err);
42 #endif
43 
44     if (err == -1) {
45 #ifdef MPICH2
46 	*error_code = MPIR_Err_create_code(MPI_SUCCESS, MPIR_ERR_RECOVERABLE, myname, __LINE__, MPI_ERR_IO, "**io",
47 	    "**io %s", strerror(errno));
48 #elif defined(PRINT_ERR_MSG)
49 	*error_code =  MPI_ERR_UNKNOWN;
50 #else
51 	*error_code = MPIR_Err_setmsg(MPI_ERR_IO, MPIR_ADIO_ERROR,
52 			      myname, "I/O Error", "%s", strerror(errno));
53 	ADIOI_Error(fd, *error_code, myname);
54 #endif
55     }
56     else *error_code = MPI_SUCCESS;
57 }
58 
59 
60 
ADIOI_PIOFS_WriteStrided(ADIO_File fd,void * buf,int count,MPI_Datatype datatype,int file_ptr_type,ADIO_Offset offset,ADIO_Status * status,int * error_code)61 void ADIOI_PIOFS_WriteStrided(ADIO_File fd, void *buf, int count,
62                        MPI_Datatype datatype, int file_ptr_type,
63                        ADIO_Offset offset, ADIO_Status *status, int
64                        *error_code)
65 {
66 /* Since PIOFS does not support file locking, can't do buffered writes
67    as on Unix */
68 
69 /* offset is in units of etype relative to the filetype. */
70 
71     ADIOI_Flatlist_node *flat_buf, *flat_file;
72     struct iovec *iov;
73     int i, j, k, err=-1, bwr_size, fwr_size=0, st_index=0;
74     int bufsize, num, size, sum, n_etypes_in_filetype, size_in_filetype;
75     int n_filetypes, etype_in_filetype;
76     ADIO_Offset abs_off_in_filetype=0;
77     int filetype_size, etype_size, buftype_size;
78     MPI_Aint filetype_extent, buftype_extent, indx;
79     int buf_count, buftype_is_contig, filetype_is_contig;
80     ADIO_Offset off, disp;
81     int flag, new_bwr_size, new_fwr_size, err_flag=0;
82 #ifndef PRINT_ERR_MSG
83     static char myname[] = "ADIOI_PIOFS_WRITESTRIDED";
84 #endif
85 
86     if (fd->atomicity) {
87 	FPRINTF(stderr, "ROMIO cannot guarantee atomicity of noncontiguous accesses in atomic mode, as PIOFS doesn't support file locking. Use nonatomic mode and its associated semantics.\n");
88 	MPI_Abort(MPI_COMM_WORLD, 1);
89     }
90 
91     ADIOI_Datatype_iscontig(datatype, &buftype_is_contig);
92     ADIOI_Datatype_iscontig(fd->filetype, &filetype_is_contig);
93 
94     MPI_Type_size(fd->filetype, &filetype_size);
95     if ( ! filetype_size ) {
96 	*error_code = MPI_SUCCESS;
97 	return;
98     }
99 
100     MPI_Type_extent(fd->filetype, &filetype_extent);
101     MPI_Type_size(datatype, &buftype_size);
102     MPI_Type_extent(datatype, &buftype_extent);
103     etype_size = fd->etype_size;
104 
105     bufsize = buftype_size * count;
106 
107     if (!buftype_is_contig && filetype_is_contig) {
108 
109 /* noncontiguous in memory, contiguous in file. use writev */
110 
111 	ADIOI_Flatten_datatype(datatype);
112 	flat_buf = ADIOI_Flatlist;
113 	while (flat_buf->type != datatype) flat_buf = flat_buf->next;
114 
115 /* There is a limit of 16 on the number of iovecs for readv/writev! */
116 
117 	iov = (struct iovec *) ADIOI_Malloc(16*sizeof(struct iovec));
118 
119 	if (file_ptr_type == ADIO_EXPLICIT_OFFSET) {
120 	    off = fd->disp + etype_size * offset;
121 	    llseek(fd->fd_sys, off, SEEK_SET);
122 	}
123 	else off = llseek(fd->fd_sys, fd->fp_ind, SEEK_SET);
124 
125 	k = 0;
126 	for (j=0; j<count; j++)
127 	    for (i=0; i<flat_buf->count; i++) {
128 		iov[k].iov_base = ((char *) buf) + j*buftype_extent +
129 		    flat_buf->indices[i];
130 		iov[k].iov_len = flat_buf->blocklens[i];
131 		/*FPRINTF(stderr, "%d %d\n", iov[k].iov_base, iov[k].iov_len);*/
132 
133 		off += flat_buf->blocklens[i];
134 		k = (k+1)%16;
135 
136 		if (!k) {
137 		    err = writev(fd->fd_sys, iov, 16);
138 		    if (err == -1) err_flag = 1;
139 		}
140 	    }
141 
142 	if (k) {
143 	    err = writev(fd->fd_sys, iov, k);
144 	    if (err == -1) err_flag = 1;
145 	}
146 
147 	if (file_ptr_type == ADIO_INDIVIDUAL) fd->fp_ind = off;
148 
149 	ADIOI_Free(iov);
150 	if (err_flag) {
151 #ifdef MPICH2
152 	    *error_code = MPIR_Err_create_code(MPI_SUCCESS, MPIR_ERR_RECOVERABLE, myname, __LINE__, MPI_ERR_IO, "**io",
153 		"**io %s", strerror(errno));
154 #elif defined(PRINT_ERR_MSG)
155 	    *error_code =  MPI_ERR_UNKNOWN;
156 #else /* MPICH-1 */
157 	    *error_code = MPIR_Err_setmsg(MPI_ERR_IO, MPIR_ADIO_ERROR,
158 			      myname, "I/O Error", "%s", strerror(errno));
159 	    ADIOI_Error(fd, *error_code, myname);
160 #endif
161 	}
162 	else *error_code = MPI_SUCCESS;
163     } /* if (!buftype_is_contig && filetype_is_contig) ... */
164 
165     else {  /* noncontiguous in file */
166 
167 /* split up into several contiguous writes */
168 
169 /* find starting location in the file */
170 
171 /* filetype already flattened in ADIO_Open */
172 	flat_file = ADIOI_Flatlist;
173 	while (flat_file->type != fd->filetype) flat_file = flat_file->next;
174         disp = fd->disp;
175 
176 	if (file_ptr_type == ADIO_INDIVIDUAL) {
177 	    offset = fd->fp_ind; /* in bytes */
178             n_filetypes = -1;
179             flag = 0;
180             while (!flag) {
181                 n_filetypes++;
182                 for (i=0; i<flat_file->count; i++) {
183                     if (disp + flat_file->indices[i] +
184                         (ADIO_Offset) n_filetypes*filetype_extent + flat_file->blocklens[i]
185                             >= offset) {
186                         st_index = i;
187                         fwr_size = disp + flat_file->indices[i] +
188                                 (ADIO_Offset) n_filetypes*filetype_extent
189                                  + flat_file->blocklens[i] - offset;
190                         flag = 1;
191                         break;
192                     }
193                 }
194             }
195 	}
196 	else {
197 	    n_etypes_in_filetype = filetype_size/etype_size;
198 	    n_filetypes = (int) (offset / n_etypes_in_filetype);
199 	    etype_in_filetype = (int) (offset % n_etypes_in_filetype);
200 	    size_in_filetype = etype_in_filetype * etype_size;
201 
202 	    sum = 0;
203 	    for (i=0; i<flat_file->count; i++) {
204 		sum += flat_file->blocklens[i];
205 		if (sum > size_in_filetype) {
206 		    st_index = i;
207 		    fwr_size = sum - size_in_filetype;
208 		    abs_off_in_filetype = flat_file->indices[i] +
209 			size_in_filetype - (sum - flat_file->blocklens[i]);
210 		    break;
211 		}
212 	    }
213 
214 	    /* abs. offset in bytes in the file */
215             offset = disp + (ADIO_Offset) n_filetypes*filetype_extent + abs_off_in_filetype;
216 	}
217 
218 	if (buftype_is_contig && !filetype_is_contig) {
219 
220 /* contiguous in memory, noncontiguous in file. should be the most
221    common case. */
222 
223 	    i = 0;
224 	    j = st_index;
225 	    off = offset;
226 	    fwr_size = ADIOI_MIN(fwr_size, bufsize);
227 	    while (i < bufsize) {
228                 if (fwr_size) {
229                     /* TYPE_UB and TYPE_LB can result in
230                        fwr_size = 0. save system call in such cases */
231 		    llseek(fd->fd_sys, off, SEEK_SET);
232 		    err = write(fd->fd_sys, ((char *) buf) + i, fwr_size);
233 		    if (err == -1) err_flag = 1;
234 		}
235 		i += fwr_size;
236 
237                 if (off + fwr_size < disp + flat_file->indices[j] +
238                    flat_file->blocklens[j] + (ADIO_Offset) n_filetypes*filetype_extent)
239                        off += fwr_size;
240                 /* did not reach end of contiguous block in filetype.
241                    no more I/O needed. off is incremented by fwr_size. */
242                 else {
243 		    if (j < (flat_file->count - 1)) j++;
244 		    else {
245 			j = 0;
246 			n_filetypes++;
247 		    }
248 		    off = disp + flat_file->indices[j] +
249                                         (ADIO_Offset) n_filetypes*filetype_extent;
250 		    fwr_size = ADIOI_MIN(flat_file->blocklens[j], bufsize-i);
251 		}
252 	    }
253 	}
254 	else {
255 /* noncontiguous in memory as well as in file */
256 
257 	    ADIOI_Flatten_datatype(datatype);
258 	    flat_buf = ADIOI_Flatlist;
259 	    while (flat_buf->type != datatype) flat_buf = flat_buf->next;
260 
261 	    k = num = buf_count = 0;
262 	    indx = flat_buf->indices[0];
263 	    j = st_index;
264 	    off = offset;
265 	    bwr_size = flat_buf->blocklens[0];
266 
267 	    while (num < bufsize) {
268 		size = ADIOI_MIN(fwr_size, bwr_size);
269 		if (size) {
270 		    llseek(fd->fd_sys, off, SEEK_SET);
271 		    err = write(fd->fd_sys, ((char *) buf) + indx, size);
272 		    if (err == -1) err_flag = 1;
273 		}
274 
275 		new_fwr_size = fwr_size;
276 		new_bwr_size = bwr_size;
277 
278 		if (size == fwr_size) {
279 /* reached end of contiguous block in file */
280                     if (j < (flat_file->count - 1)) j++;
281                     else {
282                         j = 0;
283                         n_filetypes++;
284                     }
285 
286                     off = disp + flat_file->indices[j] +
287                                               (ADIO_Offset) n_filetypes*filetype_extent;
288 
289 		    new_fwr_size = flat_file->blocklens[j];
290 		    if (size != bwr_size) {
291 			indx += size;
292 			new_bwr_size -= size;
293 		    }
294 		}
295 
296 		if (size == bwr_size) {
297 /* reached end of contiguous block in memory */
298 
299 		    k = (k + 1)%flat_buf->count;
300 		    buf_count++;
301 		    indx = buftype_extent*(buf_count/flat_buf->count) +
302 			flat_buf->indices[k];
303 		    new_bwr_size = flat_buf->blocklens[k];
304 		    if (size != fwr_size) {
305 			off += size;
306 			new_fwr_size -= size;
307 		    }
308 		}
309 		num += size;
310 		fwr_size = new_fwr_size;
311                 bwr_size = new_bwr_size;
312 	    }
313 	}
314 
315         if (file_ptr_type == ADIO_INDIVIDUAL) fd->fp_ind = off;
316 	if (err_flag) {
317 #ifdef MPICH2
318 	    *error_code = MPIR_Err_create_code(MPI_SUCCESS, MPIR_ERR_RECOVERABLE, myname, __LINE__, MPI_ERR_IO, "**io",
319 		"**io %s", strerror(errno));
320 #elif defined(PRINT_ERR_MSG)
321 	    *error_code = MPI_ERR_UNKNOWN;
322 #else /* MPICH-1 */
323 	    *error_code = MPIR_Err_setmsg(MPI_ERR_IO, MPIR_ADIO_ERROR,
324 			      myname, "I/O Error", "%s", strerror(errno));
325 	    ADIOI_Error(fd, *error_code, myname);
326 #endif
327 	}
328 	else *error_code = MPI_SUCCESS;
329     }
330 
331     fd->fp_sys_posn = -1;   /* set it to null. */
332 
333 #ifdef HAVE_STATUS_SET_BYTES
334     MPIR_Status_set_bytes(status, datatype, bufsize);
335 /* This is a temporary way of filling in status. The right way is to
336    keep track of how much data was actually written by ADIOI_BUFFERED_WRITE. */
337 #endif
338 
339     if (!buftype_is_contig) ADIOI_Delete_flattened(datatype);
340 }
341