2
/* $Log: sequential.c,v $
3
/* Revision 1.3 2003/04/22 14:59:26 crinders
4
/* Corrected error in sequential.c with an incorrect fprintf on line 476 ud->unit and caller were switched.
6
/* Revision 1.2 2002/04/19 21:48:06 sherrill
7
/* Remove some unused functions and do doxygen markup of libciomr.
9
/* Revision 1.1.1.1 2000/02/04 22:53:23 evaleev
10
/* Started PSI 3 repository
12
/* Revision 2.11 1997/09/14 03:28:55 sherrill
13
/* Added iosize_() to types.h so the function prototype could be passed to
14
/* flen.c, which was getting the wrong return type. Also reformatted some
15
/* of my old code just a little to make it look a bit nicer.
17
* Revision 2.10 1997/09/12 13:53:04 crawdad
18
* Changing marco name from ULL to PSI_FPTR.
20
* Revision 2.9 1997/08/25 21:50:08 crawdad
21
* Making changes for extension of PSI file size limit.
23
* Revision 2.8 1997/06/23 12:26:00 crawdad
24
* Multiple changes to libciomr: Moved "param.h" to "iomrparam.h" to avoid
25
* conflicts with similarly named system file under linux. Corrected type
26
* casting in rread(), rwrit(), sread(), and swrit() functions. Corrected
27
* unclosed tmpdisks.dat file in sequential.c. Corrected block_matrix() to
28
* avoid malloc'ing zero-length arrays.
32
* Revision 2.7 1996/07/02 21:06:30 sherrill
33
* Completed the changes needed to use unit numbers greater than 99; changed
34
* a hardwired 99 in init_ptrs.c to MAX_UNIT and increased a "unit" string
35
* from 3 chars to 4. Also removed a compiler warning in sequential.c by
36
* casting ud to (char *) for malloc_check().
38
* Revision 2.6 1996/06/18 20:47:47 sherrill
39
* Add the whole set of int_array routines to int_array.c (replacing
40
* init_int_array.c), add block_matrix.c, and add a new function flen
41
* which gets the file size for unit number x.
43
* Revision 2.5 1995/04/01 20:53:06 fermann
44
* changed bytewise file pointers such as first, last and length to long
45
* unsigned ints in order to handle up to 4 gigabyte tmp files (striped into
46
* individual pieces of less than 2 gigabytes). added functions li2sec and
47
* sec2li for where they are needed.
49
* Revision 2.4 1994/06/02 02:28:02 seidl
50
* use SITEDIR for location of tmpdisks.dat
52
* Revision 1.1 1994/05/02 23:11:21 cljanss
53
* CCQC code as of May 1, 1994 that was missed in the initial cvs checkin.
55
* Revision 2.3 1993/09/08 20:00:59 psi
56
* Add default disk striping
58
* Revision 2.2 1991/09/18 20:47:30 seidl
61
* Revision 2.1 1991/06/15 18:30:03 seidl
62
* *** empty log message ***
65
static char *rcsid = "$Id: sequential.c,v 1.3 2003/04/22 14:59:26 crinders Exp $";
70
#include "iomrparam.h"
77
char* getenv(const char*);
81
#define FILENAME_MAX 512
85
#define TMP_VOL_MAX 10 /* max number of tmp drives */
89
static char open_name[] = "sequential_ioopen";
92
sequential_ioopen(baseparam,unit)
98
char param[MAX_STRING];
99
char volid[MAX_STRING];
100
char name[MAX_STRING];
101
char volpath[MAX_STRING];
102
char path[MAX_STRING];
104
struct stat statjunk;
106
/* This file contains a list of files to be deleted
107
* when we are using batch. */
109
/* If we are running in batch then this is set to the $(MBATCH)
110
* environment variable to indicate the job_id. */
113
char cleanfile[FILENAME_MAX];
115
/* CDS 9/93 New variables for automatic tmp drive determination */
116
char endofvolpath[MAX_STRING] ; /* last part of volume path string */
117
int got_first_volpath ; /* flag for getting first volume path */
118
int use_default_vols=0 ; /* flag whether to use default tmp vols */
119
int num_temp_vols; /* number of tmp drives ava */
120
int temp_vol[TMP_VOL_MAX] ; /* vector of physical tmp drive numbers */
121
int get_tempinfo() ; /* func which reads temp drive datafile */
122
int junk ; /* temp variable */
123
/* CDS 9/93 End of new variables */
126
/* Look at the environment to see if this is a batch job. */
127
if (!(mbatchc = getenv("MBATCH="))) {
131
job_id = atoi(mbatchc);
132
sprintf(cleanfile,"Batch_Clean.%05d",job_id);
133
/* If the file has not yet been open, then open it and
134
* tell it that we want it to delete itself. */
135
if (stat(cleanfile,&statjunk)!=0) {
136
cleanfilep = fopen(cleanfile,"a");
138
fprintf(stderr,"sequential I/O: couldn't open %s\n",cleanfile);
141
fseek(cleanfilep,(long)0,SEEK_END);
142
fprintf(cleanfilep,"%s\n",cleanfile);
148
strcpy(name_format,"%s");
150
/* Allocate memory for the unit descriptor. */
151
ud = (sequential_t *) malloc(sizeof(sequential_t));
152
malloc_check(open_name,(char *) ud);
154
/* Find out if we want extra information to be printed about this
155
* unit. name is used as a temporary buffer here. */
156
strcpy(param,baseparam);
158
oldinp = oldstyleinput();
160
strcat(param,"verbose");
161
if (get_param(param,"%s",name)== -1) ud->verbose = 0;
163
if (!strcmp(name,"on")) ud->verbose = 1;
164
else if (!strcmp(name,"yes")) ud->verbose = 1;
165
else if (!strcmp(name,"y")) ud->verbose = 1;
166
else ud->verbose = 0;
170
strcat(param,"VERBOSE");
171
if (get_file_info(param,"%s",name)== -1) ud->verbose = 0;
173
if (!strcmp(name,"ON")) ud->verbose = 1;
174
else if (!strcmp(name,"YES")) ud->verbose = 1;
175
else if (!strcmp(name,"Y")) ud->verbose = 1;
176
else if (!strcmp(name,"TRUE")) ud->verbose = 1;
177
else if (!strcmp(name,"1")) ud->verbose = 1;
178
else ud->verbose = 0;
182
/* See if we want to keep this file when we are done. */
183
/* Setting job_id = 0 causes the file to be kept. */
184
strcpy(param,baseparam);
186
strcat(param,"keep");
187
if (!(get_param(param,"%s",name)== -1)) {
188
if (!strcmp(name,"on")) job_id = 0;
189
else if (!strcmp(name,"1")) job_id = 0;
190
else if (!strcmp(name,"yes")) job_id = 0;
191
else if (!strcmp(name,"y")) job_id = 0;
195
strcat(param,"KEEP");
196
if (!(get_file_info(param,"%s",name)== -1)) {
197
if (!strcmp(name,"ON")) job_id = 0;
198
else if (!strcmp(name,"1")) job_id = 0;
199
else if (!strcmp(name,"YES")) job_id = 0;
200
else if (!strcmp(name,"TRUE")) job_id = 0;
201
else if (!strcmp(name,"Y")) job_id = 0;
205
/* Find out how many volumes to place the unit across. */
206
strcpy(param,baseparam);
209
if (get_param(param,"%d",&ud->n) == -1) {
211
use_default_vols = 1 ;
215
strcat(param,"NVOLUME");
216
if (get_file_info(param,"%d",&ud->n) == -1) {
218
use_default_vols = 1 ;
221
if (ud->n == 0) { ud->n = 1; use_default_vols = 1; }
223
/* Set up the block size for this file system. */
224
strcpy(param,baseparam);
226
strcat(param,"blocksize");
227
if (get_param(param,"%d",&ud->blocksize) == -1) ud->blocksize = 8192;
230
strcat(param,"BLOCKSIZE");
231
if (get_file_info(param,"%d",&ud->blocksize) == -1) ud->blocksize = 8192;
233
if (ud->blocksize == 0) ud->blocksize = 8192;
235
/* Find out how the files are to be named. */
237
if (get_param("FILES:name",name_format,name) == -1)
238
strcpy(name,"sequential");
241
strcpy(param,baseparam);
242
strcat(param,"NAME");
243
if (get_file_info(param,name_format,name) == -1)
244
strcpy(name,"sequential");
247
/* CDS 9/93 modified code begins here -- check how many temp drives ava */
248
got_first_volpath = 1 ;
250
sprintf(param,"%s%d",baseparam,1);
251
if (get_param(param,"%s",volpath) == -1) got_first_volpath = 0 ;
254
sprintf(param,"%s%s%d",baseparam,"VOLUME",1);
255
if (get_file_info(param,"%s",volpath) == -1) got_first_volpath = 0 ;
258
/* fprintf(stdout, "sequential_ioopen: Got volpath1 = %s\n",volpath); */
260
if (got_first_volpath && use_default_vols) {
261
if (strncmp("/tmp",volpath,4)==0) { /*ch defaults for tmp files only*/
262
if (!get_tempinfo(&num_temp_vols, temp_vol) ) {
263
/* if we couldn't read the datafile, abort */
264
fprintf(stderr, "sequential_ioopen: can't read default tmp drive file\n") ;
267
ud->n = num_temp_vols ;
270
/* CDS 9/93 Finished getting temp drive info and setting num of volumes */
272
for (i=0; i<ud->n; i++) {
274
sprintf(param,"%s%d",baseparam,i);
275
if (get_param(param,"%s",volpath) == -1) {
276
if (ud->n > 1) no_path_given(open_name);
277
else volpath[0] = '\0';
281
sprintf(param,"%s%s%d",baseparam,"VOLUME",i+1);
282
if (get_file_info(param,"%s",volpath) == -1) {
283
if (ud->n > 1) no_path_given(open_name);
284
else volpath[0] = '\0';
288
/* CDS 9/93 Now check again if tmp file and use_default_vols *
289
* If so, fix vol number in pathnames */
290
if (use_default_vols && (strncmp("/tmp", volpath, 4)==0)) {
291
sscanf(volpath, "/tmp%d%s", &junk, endofvolpath) ;
292
sprintf(volpath, "/tmp%d%s", temp_vol[i], endofvolpath) ;
293
/* fprintf(stdout,"sequential_ioopen:Volpath %d = %s\n",i,volpath); */
295
/* CDS 9/93 Ok, that's all the changes except for the new function at end */
297
sprintf(path,"%s%s%c%d",volpath,name,'.',unit);
298
ud->v[i].path = (char *) malloc(strlen(path)+1);
299
malloc_check(open_name,ud->v[i].path);
300
strcpy(ud->v[i].path,path);
302
/* Any file for with keep is given is kept, otherwise, any
303
* file which has a /tmp as the first four characters in the
305
if (job_id&&(!strncmp("/tmp",path,4))) {
306
cleanfilep = fopen(cleanfile,"a");
308
fprintf(stderr,"sequential I/O: couldn't open %s\n",cleanfile);
311
fseek(cleanfilep,(long)0,SEEK_END);
312
fprintf(cleanfilep,"%s\n",path);
318
if (stat(ud->v[i].path,&statjunk)==0) mode = "r+";
320
ud->v[i].stream = fopen(ud->v[i].path,mode);
321
fopen_check(open_name,ud->v[i].path,ud->v[i].stream);
323
ud->v[i].stream = open(ud->v[i].path,O_RDWR|O_CREAT,0644);
324
/* fprintf(stderr, "Stream = %d\n",ud->v[i].stream); */
331
ud->previous_size = 0;
335
fprintf(stderr,"SEQ_IO: opened unit %d {\n",unit);
336
fprintf(stderr," blocksize = %d\n",ud->blocksize);
337
for (i=0; i<ud->n; i++) {
338
fprintf(stderr," v[%d].path = \"%s\"\n",i,ud->v[i].path);
340
fprintf(stderr," }\n");
346
sequential_ioclos(ud,status)
352
for (i=0; i<ud->n; i++) {
354
fclose(ud->v[i].stream);
356
close(ud->v[i].stream);
358
if (status == 4) unlink(ud->v[i].path);
360
ud->v[i].path = NULL;
363
fprintf(stderr,"SEQ_IO: closed unit %d {\n",ud->unit);
364
fprintf(stderr," incount = %lu\n",ud->incount);
365
fprintf(stderr," outcount = %lu\n",ud->outcount);
366
fprintf(stderr," }\n");
371
sequential_iordr(ud,buffer,first,length)
377
ud->incount += length;
378
sequential_iordwrr("sequential_iordr",IOOP_READ,ud,buffer,first,length);
382
sequential_iowrr(ud,buffer,first,length)
388
ud->outcount += length;
389
sequential_iordwrr("sequential_iowrr",IOOP_WRITE,ud,buffer,first,length);
393
sequential_iordwrr(caller,ioop,ud,buffer,first,length)
402
PSI_FPTR firstbyte, lastbyte;
403
PSI_FPTR firstblock, lastblock;
406
PSI_FPTR remainingbytes;
407
PSI_FPTR remainingseek;
409
PSI_FPTR offset1, offset2;
414
lastbyte = first + length - 1;
416
ncycles = firstbyte/(ud->n*ud->blocksize);
417
remainingseek = firstbyte -
418
ncycles*((PSI_FPTR) ud->n)*((PSI_FPTR) ud->blocksize);
420
/* fprintf(stderr, "ncycles = %lu firstbyte = %lu remainingseek = %lu\n",
421
ncycles,firstbyte,remainingseek); */
422
fullvol = remainingseek/ud->blocksize;
424
offset2 = ncycles * ud->blocksize;
425
offset1 = offset2 + ud->blocksize;
427
/* Seek all volumes to the appropiate positions. */
428
if ((ud->next != firstbyte)||(ud->last_ioop != ioop)) {
429
for (i=0; i<ud->n; i++) {
431
if (i < fullvol) offset = offset1;
432
else if (i == fullvol) offset = offset2 + remainingseek%ud->blocksize;
433
else offset = offset2;
435
fprintf(stdout,"seeking volume %d to %ld\n",i,offset);
438
if (fseek(ud->v[i].stream, offset, SEEK_SET)) {
439
fprintf(stderr,"%s: fseek: offset = %ld, vol = %d\n",caller,offset,i);
444
if (lseek(ud->v[i].stream, offset, SEEK_SET)<0) {
445
fprintf(stderr,"%s: fseek: offset = %ld, vol = %d\n",caller,offset,i);
451
if (length > 0) ud->last_ioop = ioop;
453
ud->next = lastbyte + 1;
457
len = ud->blocksize - remainingseek%ud->blocksize;
458
remainingbytes = lastbyte - firstbyte + 1;
460
fprintf(stdout,"%s: len=%ld,remainingbytes=%ld,firstbyte=%ld,lastbyte=%ld,i=%ld\n",
461
caller,len,remainingbytes,firstbyte,lastbyte,i);
464
while (remainingbytes > 0) {
465
if (len > remainingbytes) len = remainingbytes;
467
fprintf(stdout," len=%ld,remainingbytes=%ld,i=%ld\n",
468
len,remainingbytes,i);
470
if (ioop == IOOP_READ) {
472
if (fread(&buffer[ibuf],len,1,ud->v[i].stream)!=1) {
473
fprintf(stderr,"%s: len = %ld, volume = %ld\n",caller,len,i);
474
if (ferror(ud->v[i].stream)) fread_error(caller);
477
if (read(ud->v[i].stream,&buffer[ibuf],len)<1) {
478
fprintf(stderr,"%s: unit = %ld, len = %ld, volume = %ld\n",
479
caller, ud->unit,len,i);
484
else if (ioop == IOOP_WRITE) {
486
if (fwrite(&buffer[ibuf],len,1,ud->v[i].stream)!=1) {
487
fprintf(stderr,"%s: len = %ld, volume = %ld\n",caller,len,i);
488
if (ferror(ud->v[i].stream)) fwrite_error(caller);
491
if ((write(ud->v[i].stream,&buffer[ibuf],len))!=len) {
492
fprintf(stderr,"%s: len = %ld, volume = %ld\n",caller,len,i);
493
fwrite_error(caller);
498
fprintf(stderr,"%s: illegal ioop = %d\n",caller,ioop);
503
remainingbytes -= len;
512
** This function determines the file size (bytes) for a given unit
513
** David Sherrill, June 1996
515
PSI_FPTR sequential_iosize(ud)
522
for (i=0; i<ud->n; i++) {
523
errcod = stat(ud->v[i].path, &fstat);
525
fprintf(stderr,"sequential_iosize: can't access %s\n",
529
fsize += fstat.st_size;
540
** GET_TEMPINFO : David Sherrill, April 1993
542
** This function will allow PSI to figure out how many temp drives
543
** to use for sequential io. The data will be contained in a
544
** host table file listing each host, the number of temp drives
545
** it has, and the number labels for each of these drives
548
** num_temp_vols = ptr to number of temp vols to use
549
** temp_vol = array of physical temp disks to use
550
** (i.e. {1 2} to use /tmp1 and /tmp2)
552
** Returns: 1 for success, 0 otherwise
555
#define HOSTNAME_MAX 26
558
get_tempinfo(num_temp_vols, temp_vol)
559
int *num_temp_vols, *temp_vol ;
561
FILE *fpi ; /* for reading in the host table data */
562
char hostname[HOSTNAME_MAX] ; /* name of machine we're running on */
563
char *hostfile; /* filename containing tmp disk info */
564
char line[MAX_STRING] ; /* hold line from hostfile */
565
int found = 0 ; /* is host found in data file ? */
566
char *sptr ; /* keep place in input string */
569
hostfile = SITEDIR "/tmpdisks.dat" ;
571
/* open data file on hosts' temp disks */
572
fpi = fopen(hostfile, "r");
574
/* open datafile on hosts' temp disks */
576
fprintf(stderr, "get_tempinfo: couldn't open %s\n", hostfile);
582
if (gethostname(hostname,HOSTNAME_MAX) == -1) {
583
fprintf(stderr, "get_tempinfo: trouble getting hostname\n") ;
588
/* fprintf(stdout, "get_tempinfo: got hostname = %s\n", hostname) ; */
590
/* scan for that hostname in the datafile, get the info */
591
while (io_getline(fpi, line) != -1) {
592
if (strstr(line, hostname)) { found = 1 ; break ; }
595
fprintf(stdout, "get_tempinfo: no host %s in datafile\n", hostname) ;
600
else { /* get the info */
601
if ( (sptr = strchr(line, '=')) == NULL) {
602
fprintf(stderr, "get_tempinfo: %s has bad format\n", hostfile) ;
607
while ( (*sptr == ' ') && (*sptr != '\0') ) sptr++ ;
609
if (sscanf(sptr, "%d", num_temp_vols) != 1) {
610
fprintf(stderr, "get_tempinfo: %s has bad format\n", hostfile) ;
615
if (*num_temp_vols > TMP_VOL_MAX) {
616
fprintf(stderr, "get_tempinfo: %d exceeds %d maximum vols\n",
617
*num_temp_vols, TMP_VOL_MAX) ;
618
*num_temp_vols = TMP_VOL_MAX ;
621
for (i=0; i<(*num_temp_vols); i++) {
622
while ( (*sptr != ' ') && (*sptr != '\0') ) sptr++ ;
623
while ( (*sptr == ' ') && (*sptr != '\0') ) sptr++ ;
625
fprintf(stderr, "get_tempinfo: %s bad format\n", hostfile) ;
629
if (sscanf(sptr, "%d", &data_in) != 1) {
630
fprintf(stderr, "get_tempinfo: %s has bad format\n", hostfile) ;
634
else temp_vol[i] = data_in ;
638
fprintf(stdout, "get_tempinfo: got %d vols : ", *num_temp_vols) ;
639
for (i=0; i<(*num_temp_vols); i++) {
640
fprintf(stdout, "%d ", temp_vol[i]) ;
642
fprintf(stdout, "\n") ;