summaryrefslogtreecommitdiffstats
path: root/test/atomic_reader.c
blob: 12e2d5cd6e988e4c743540f0b4d75be1f073d9f6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * Copyright by The HDF Group.                                               *
 * All rights reserved.                                                      *
 *                                                                           *
 * This file is part of HDF5.  The full HDF5 copyright notice, including     *
 * terms governing use, modification, and redistribution, is contained in    *
 * the COPYING file, which can be found at the root of the source code       *
 * distribution tree, or in https://www.hdfgroup.org/licenses.               *
 * If you do not have access to either file, you may request a copy from     *
 * help@hdfgroup.org.                                                        *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*-------------------------------------------------------------------------
 *
 * Created:     atomic_reader.c
 *
 * Purpose:     This is the "reader" part of the standalone test to check
 *              atomic read-write operation on a system.
 *              a) atomic_reader.c--the reader (this file)
 *              a) atomic_writer.c--the writer
 *              c) atomic_data--the name of the data file used by writer and reader
 *
 *-------------------------------------------------------------------------
 */

/***********/
/* Headers */
/***********/

#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#if !defined(WIN32) && !defined(__MINGW32__)

#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>

/****************/
/* Local Macros */
/****************/

#define FILENAME   "atomic_data"
#define READ_TRIES 20
#define OPEN_TRIES 50

/********************/
/* Local Prototypes */
/********************/

static void usage(void);
int         verify(int fd, unsigned int k);
void        print_info(int *info, unsigned int lastr, unsigned iteration);

/*-------------------------------------------------------------------------
 * Function:    usage
 *
 * Purpose:     To print the command line options
 *
 * Parameters:  None
 *
 * Return:     void
 *
 *-------------------------------------------------------------------------
 */
static void
usage(void)
{
    printf("\n");
    printf("Usage error!\n");
    printf("Usage: atomic_reader -n <number of integers to read> -i <number of iterations for reader>\n");
    printf("       Note**The number of integers for option n has to be positive\n");
    printf("       Note**The number of integers for option i has to be positive\n");
    printf("\n");
} /* usage() */

/*-------------------------------------------------------------------------
 * Function:    verify
 *
 * Purpose:     To verify that the data read is the pattern expected.
 *              Each integer read should be the same as the index.
 *              When a difference is encountered, the remaining integers
 *              read should be the same as the previous index.
 *              For example, the pattern expected should be either:
 *              a) 01234567....n-1
 *                  or
 *              b) if at index 4, a difference is encountered,
 *                 the remaining integers should be all "3"s as:
 *                 012333333333333
 *
 * Parameters:
 *              fd -- the file descriptor
 *              k -- the number of integers to read
 *
 * Return:
 *              positive on success
 *              negative on failure
 *
 *-------------------------------------------------------------------------
 */
int
verify(int fd, unsigned int k)
{
    unsigned int  i;          /* local index variable */
    ssize_t       bytes_read; /* the number of bytes read */
    unsigned int *buf = NULL; /* buffer to hold data read */

    /* Allocate buffer for data read */
    if ((buf = (unsigned int *)malloc(k * sizeof(unsigned int))) == NULL) {
        printf("READER: error from malloc\n");
        goto error;
    } /* end if */

    /* Position the file at the beginning */
    if (lseek(fd, 0, SEEK_SET) < 0) {
        printf("READER: error from lseek\n");
        goto error;
    } /* end if */

    /* Read the whole file */
    if ((bytes_read = read(fd, buf, (k * sizeof(unsigned int)))) < 0) {
        printf("READER: error from read\n");
        goto error;
    } /* end if */

    /* Verify the bytes read are correct */
    if (bytes_read != (ssize_t)(k * sizeof(unsigned int))) {
        printf("READER: error from bytes read=%lu\n", (unsigned long)bytes_read);
        goto error;
    } /* end if */

    /* Verify data read */
    for (i = 0; i < k; i++) {
        if (buf[i] != i)
            break;
    } /* end for */

    if (i < k) {
        /* Compare the beginning and ending sentinel values */
        if (buf[k - 1] != (i - 1)) {
            printf("FAIL IN READER: ...beginning sentinel value=%u, i=%u\n", (i - 1), i);
            printf("FAIL IN READER: buf[%u]=%u\n", i - 1, buf[i - 1]);
            printf("FAIL IN READER: buf[%u]=%u\n", i, buf[i]);
            printf("FAIL IN READER: buf[%u]=%u\n", i + 1, buf[i + 1]);
            printf("FAIL IN READER: ...ending sentinel value=%u\n", buf[k - 1]);
            goto error;
        } /* end if */
    }     /* end if */

    /* Free the buffer */
    if (buf)
        free(buf);
    return 0;

error:
    /* Free the buffer */
    if (buf)
        free(buf);
    return -1;
} /* end verify() */

/*-------------------------------------------------------------------------
 * Function:    print_info
 *
 * Purpose:     To print the statistics gathered for re-reads
 *
 * Parameters:
 *              info -- the array storing the statistics for re-reads
 *              lastr -- the last read completed
 *              iteration -- the current iteration
 *
 * Return:      void
 *
 *-------------------------------------------------------------------------
 */
void
print_info(int *info, unsigned int lastr, unsigned iteration)
{
    unsigned j; /* local index variable */

    printf("--------statistics for %u reads (iteration %u)--------\n", lastr, iteration);

    for (j = 0; j <= READ_TRIES; j++)
        printf("# of %u re-tries = %u\n", j, info[j]);

    printf("--------end statistics for %u reads (iteration %u)--------\n", lastr, iteration);
} /* print_info() */

/*-------------------------------------------------------------------------
 * Function:    main
 *
 * Purpose:     To verify that the data read is the pattern expected.
 *              (1) Make sure the file opens successfully and the # of bytes read is as expected
 *              (2) Iterate the reader with i iterations
 *              (3) Read and verify n integers for each iteration
 *              (4) On verification error, re-read the data at most READ_TRIES
 *                  times to see if correct data can be obtained
 *              (5) Print out statistics for the number of re-retries for each iteration
 *
 * Note:
 *      (a) The # of integers (via -n option) used by the writer and reader should be the same.
 *      (b) The data file used by the writer and reader should be the same.
 *
 * Future enhancement:
 *      1) Provide default values for n and i and allow user to run with either 0 or 1 option
 *      2) Use HDF library HD<system calls> instead of the system calls
 *      3) Handle large sized buffer (gigabytes) if needed
 *
 * Return:      Success:    EXIT_SUCCESS
 *              Failure:    EXIT_FAILURE
 *
 *-------------------------------------------------------------------------
 */
int
main(int argc, char *argv[])
{
    int          fd = -1;              /* file descriptor                      */
    unsigned int j = 0, i = 0, m = 0;  /* local index variables                */
    int          temp;                 /* temporary variable                   */
    unsigned int iterations = 0;       /* the input for "-i"                   */
    unsigned     num        = 0;       /* the input for "-n"                   */
    int          opt        = 0;       /* option char                          */
    int          info[READ_TRIES + 1]; /* re-tries statistics                  */

    /* Ensure the expected # of arguments */
    if (argc != 5) {
        usage();
        exit(EXIT_FAILURE);
    } /* end if */

    /* Parse command line options */
    while ((opt = getopt(argc, argv, "n:i:")) != -1) {
        switch (opt) {
            case 'n':
                if ((temp = atoi(optarg)) < 0) {
                    usage();
                    exit(EXIT_FAILURE);
                } /* end if */
                num = (unsigned int)temp;
                break;
            case 'i':
                if ((temp = atoi(optarg)) < 0) {
                    usage();
                    exit(EXIT_FAILURE);
                } /* end if */
                iterations = (unsigned int)temp;
                break;
            default:
                printf("Invalid option encountered\n");
                break;
        } /* end switch */
    }     /* end while */

    printf("READER: number of integers to read = %u; # of iterations = %d\n", num, iterations);

    printf("\n");
    for (i = 1; i <= iterations; i++) {
        unsigned opens = OPEN_TRIES;

        printf("READER: *****start iteration %u*****\n", i);

        /* Ensure open and file size are done properly */
        while (opens--) {
            struct stat sinfo;

            memset(&sinfo, 0, sizeof(sinfo));

            if ((fd = open(FILENAME, O_RDONLY, 0644)) < 0) {
                printf("READER: error from open--retry open again\n");
            }
            else {
                printf("READER: open succeed\n");

                if ((fstat(fd, &sinfo) == 0) && (sinfo.st_size == (off_t)(num * sizeof(unsigned int)))) {
                    printf("READER: file size is correct--%u\n", (unsigned int)sinfo.st_size);
                    break;
                } /* end if */

                printf("READER: error from fstat or file size of %u is incorrect--retry open again\n",
                       (unsigned int)sinfo.st_size);
                if (close(fd) < 0) {
                    printf("READER: error from close\n");
                    return EXIT_FAILURE;
                } /* end if */
                fd = -1;
            } /* end else */

        } /* end while */

        if (fd < 0) {
            printf("READER: *****open failure/incorrect file size for all %u tries, continue next "
                   "iteration*****\n\n",
                   OPEN_TRIES);
            continue;
        } /* end if */

        memset(info, 0, sizeof(info));

        /* Read and verify data */
        for (j = 1; j <= num; j++) {

            printf("READER: doing read %u\n", j);
            if (verify(fd, num) < 0) {
                printf("READER: error from read %u\n", j);

                /* Perform re-read to see if correct data is obtained */
                for (m = 1; m <= READ_TRIES; m++) {
                    printf("READER: ===============going to do re-read try %u\n", m);
                    if (verify(fd, num) < 0)
                        printf("READER: ===============error from re-read try %u\n", m);
                    else {
                        ++info[m];
                        printf("READER: ===============SUCCESS from re-read try %u\n", m);
                        break;
                    } /* end else */
                }     /* end for */

                if (m > READ_TRIES) {
                    printf("READER: ===============error from all re-read tries: %u\n", READ_TRIES);
                    printf("READER:*****ERROR--stop on read %u\n", j);
                    break;
                } /* end if */
            }
            else {
                ++info[0];
                printf("READER: success from read %u\n", j);
            } /* end else */

        } /* end for */

        /* Print the statistics for re-reads */
        print_info(info, j - 1, i);

        /* Close the file */
        if (close(fd) < 0) {
            printf("READER: error from close\n");
            return EXIT_FAILURE;
        } /* end if */

        printf("READER: *****end iteration %u*****\n\n", i);

    } /* end for */

    return EXIT_SUCCESS;
}

#else /* WIN32 / MINGW32 */

int
main(void)
{
    printf("Non-POSIX platform. Exiting.\n");
    return EXIT_FAILURE;
} /* end main() */

#endif /* WIN32 / MINGW32 */