X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Fcasefile.c;h=fdf033cbae672c7ae29135dd7d2cb62c8f0031a2;hb=e48df05eeeb85838526a03a3371964f5f6b14321;hp=2ff3a5742f3492ff65c719c38ebb6ebe03c96219;hpb=06f9ee45954e5e71fa7f6262dbf37defa1dbf996;p=pspp diff --git a/src/casefile.c b/src/casefile.c index 2ff3a5742f..fdf033cbae 100644 --- a/src/casefile.c +++ b/src/casefile.c @@ -37,7 +37,7 @@ #include #endif -#define IO_BUF_SIZE 8192 +#define IO_BUF_SIZE (8192 / sizeof (union value)) /* A casefile is a sequentially accessible array of immutable cases. It may be stored in memory or on disk as workspace @@ -57,7 +57,6 @@ struct casefile /* Basic data. */ struct casefile *next, *prev; /* Next, prev in global list. */ size_t value_cnt; /* Case size in `union value's. */ - size_t case_size; /* Case size in bytes. */ size_t case_acct_size; /* Case size for accounting. */ unsigned long case_cnt; /* Number of cases stored. */ enum { MEMORY, DISK } storage; /* Where cases are stored. */ @@ -71,9 +70,9 @@ struct casefile /* Disk storage. */ int fd; /* File descriptor, -1 if none. */ char *filename; /* Filename. */ - unsigned char *buffer; /* I/O buffer, NULL if none. */ - size_t buffer_used; /* Number of bytes used in buffer. */ - size_t buffer_size; /* Buffer size in bytes. */ + union value *buffer; /* I/O buffer, NULL if none. */ + size_t buffer_used; /* Number of values used in buffer. */ + size_t buffer_size; /* Buffer size in values. */ }; /* For reading out the cases in a casefile. */ @@ -86,11 +85,18 @@ struct casereader /* Disk storage. */ int fd; /* File descriptor. */ - unsigned char *buffer; /* I/O buffer. */ - size_t buffer_pos; /* Byte offset of buffer position. */ + union value *buffer; /* I/O buffer. */ + size_t buffer_pos; /* Offset of buffer position. */ struct ccase c; /* Current case. */ }; +/* Return the case number of the current case */ +unsigned long +casereader_cnum(const struct casereader *r) +{ + return r->case_idx; +} + /* Doubly linked list of all casefiles. */ static struct casefile *casefiles; @@ -107,8 +113,8 @@ static void fill_buffer (struct casereader *reader); static int safe_open (const char *filename, int flags); static int safe_close (int fd); -static int full_read (int fd, char *buffer, size_t size); -static int full_write (int fd, const char *buffer, size_t size); +static int full_read (int fd, void *buffer, size_t size); +static int full_write (int fd, const void *buffer, size_t size); /* Creates and returns a casefile to store cases of VALUE_CNT `union value's each. */ @@ -122,8 +128,7 @@ casefile_create (size_t value_cnt) cf->next->prev = cf; casefiles = cf; cf->value_cnt = value_cnt; - cf->case_size = case_serial_size (value_cnt); - cf->case_acct_size = cf->case_size + 4 * sizeof (void *); + cf->case_acct_size = (cf->value_cnt + 4) * sizeof *cf->buffer; cf->case_cnt = 0; cf->storage = MEMORY; cf->mode = WRITE; @@ -133,9 +138,9 @@ casefile_create (size_t value_cnt) cf->fd = -1; cf->filename = NULL; cf->buffer = NULL; - cf->buffer_size = ROUND_UP (cf->case_size, IO_BUF_SIZE); - if (cf->case_size > 0 && cf->buffer_size % cf->case_size > 512) - cf->buffer_size = cf->case_size; + cf->buffer_size = ROUND_UP (cf->value_cnt, IO_BUF_SIZE); + if (cf->value_cnt > 0 && cf->buffer_size % cf->value_cnt > 64) + cf->buffer_size = cf->value_cnt; cf->buffer_used = 0; register_atexit (); return cf; @@ -219,6 +224,7 @@ casefile_sleep (const struct casefile *cf_) casefile_mode_reader (cf); casefile_to_disk (cf); + flush_buffer (cf); if (cf->fd != -1) { @@ -312,9 +318,9 @@ casefile_append_xfer (struct casefile *cf, struct ccase *c) static void write_case_to_disk (struct casefile *cf, const struct ccase *c) { - case_serialize (c, cf->buffer + cf->buffer_used, cf->case_size); - cf->buffer_used += cf->case_size; - if (cf->buffer_used + cf->case_size > cf->buffer_size) + case_to_values (c, cf->buffer + cf->buffer_used, cf->value_cnt); + cf->buffer_used += cf->value_cnt; + if (cf->buffer_used + cf->value_cnt > cf->buffer_size) flush_buffer (cf); } @@ -325,42 +331,14 @@ flush_buffer (struct casefile *cf) { if (cf->buffer_used > 0) { - if (!full_write (cf->fd, cf->buffer, cf->buffer_size)) + if (!full_write (cf->fd, cf->buffer, + cf->buffer_size * sizeof *cf->buffer)) msg (FE, _("Error writing temporary file: %s."), strerror (errno)); cf->buffer_used = 0; } } -/* Creates a temporary file and stores its name in *FILENAME and - a file descriptor for it in *FD. Returns success. Caller is - responsible for freeing *FILENAME. */ -static int -make_temp_file (int *fd, char **filename) -{ - const char *parent_dir; - - assert (filename != NULL); - assert (fd != NULL); - - if (getenv ("TMPDIR") != NULL) - parent_dir = getenv ("TMPDIR"); - else - parent_dir = P_tmpdir; - - *filename = xmalloc (strlen (parent_dir) + 32); - sprintf (*filename, "%s%cpsppXXXXXX", parent_dir, DIR_SEPARATOR); - *fd = mkstemp (*filename); - if (*fd < 0) - { - msg (FE, _("%s: Creating temporary file: %s."), - *filename, strerror (errno)); - free (*filename); - *filename = NULL; - return 0; - } - return 1; -} /* If CF is currently stored in memory, writes it to disk. Readers, if any, retain their current positions. */ @@ -371,7 +349,7 @@ casefile_to_disk (const struct casefile *cf_) struct casereader *reader; assert (cf != NULL); - + if (cf->storage == MEMORY) { size_t idx, block_cnt; @@ -383,8 +361,8 @@ casefile_to_disk (const struct casefile *cf_) cf->storage = DISK; if (!make_temp_file (&cf->fd, &cf->filename)) err_failure (); - cf->buffer = xmalloc (cf->buffer_size); - memset (cf->buffer, 0, cf->buffer_size); + cf->buffer = xmalloc (cf->buffer_size * sizeof *cf->buffer); + memset (cf->buffer, 0, cf->buffer_size * sizeof *cf->buffer); case_bytes -= cf->case_cnt * cf->case_acct_size; for (idx = 0; idx < cf->case_cnt; idx++) @@ -438,13 +416,14 @@ casefile_get_reader (const struct casefile *cf_) cf->mode = READ; reader = xmalloc (sizeof *reader); - reader->cf = cf; reader->next = cf->readers; if (cf->readers != NULL) reader->next->prev = reader; - reader->prev = NULL; cf->readers = reader; + reader->prev = NULL; + reader->cf = cf; reader->case_idx = 0; + reader->destructive = 0; reader->fd = -1; reader->buffer = NULL; reader->buffer_pos = 0; @@ -482,7 +461,6 @@ static void reader_open_file (struct casereader *reader) { struct casefile *cf = reader->cf; - size_t buffer_case_cnt; off_t file_ofs; if (reader->case_idx >= cf->case_cnt) @@ -508,17 +486,17 @@ reader_open_file (struct casereader *reader) } else { - reader->buffer = xmalloc (cf->buffer_size); - memset (reader->buffer, 0, cf->buffer_size); + reader->buffer = xmalloc (cf->buffer_size * sizeof *cf->buffer); + memset (reader->buffer, 0, cf->buffer_size * sizeof *cf->buffer); } - if (cf->case_size != 0) + if (cf->value_cnt != 0) { - buffer_case_cnt = cf->buffer_size / cf->case_size; - file_ofs = ((off_t) reader->case_idx - / buffer_case_cnt * cf->buffer_size); + size_t buffer_case_cnt = cf->buffer_size / cf->value_cnt; + file_ofs = ((off_t) reader->case_idx / buffer_case_cnt + * cf->buffer_size * sizeof *cf->buffer); reader->buffer_pos = (reader->case_idx % buffer_case_cnt - * cf->case_size); + * cf->value_cnt); } else file_ofs = 0; @@ -526,7 +504,7 @@ reader_open_file (struct casereader *reader) msg (FE, _("%s: Seeking temporary file: %s."), cf->filename, strerror (errno)); - if (cf->case_cnt > 0 && cf->case_size > 0) + if (cf->case_cnt > 0 && cf->value_cnt > 0) fill_buffer (reader); case_create (&reader->c, cf->value_cnt); @@ -536,11 +514,12 @@ reader_open_file (struct casereader *reader) static void fill_buffer (struct casereader *reader) { - int retval = full_read (reader->fd, reader->buffer, reader->cf->buffer_size); + int retval = full_read (reader->fd, reader->buffer, + reader->cf->buffer_size * sizeof *reader->buffer); if (retval < 0) msg (FE, _("%s: Reading temporary file: %s."), reader->cf->filename, strerror (errno)); - else if (retval != reader->cf->buffer_size) + else if (retval != reader->cf->buffer_size * sizeof *reader->buffer) msg (FE, _("%s: Temporary file ended unexpectedly."), reader->cf->filename); } @@ -575,15 +554,15 @@ casereader_read (struct casereader *reader, struct ccase *c) } else { - if (reader->buffer_pos + reader->cf->case_size > reader->cf->buffer_size) + if (reader->buffer_pos + reader->cf->value_cnt > reader->cf->buffer_size) { fill_buffer (reader); reader->buffer_pos = 0; } - case_unserialize (&reader->c, reader->buffer + reader->buffer_pos, - reader->cf->case_size); - reader->buffer_pos += reader->cf->case_size; + case_from_values (&reader->c, reader->buffer + reader->buffer_pos, + reader->cf->value_cnt); + reader->buffer_pos += reader->cf->value_cnt; reader->case_idx++; case_clone (c, &reader->c); @@ -679,8 +658,9 @@ static int safe_close (int fd) /* Calls read(), passing FD, BUFFER, and SIZE, repeating as necessary to deal with interrupted calls. */ static int -full_read (int fd, char *buffer, size_t size) +full_read (int fd, void *buffer_, size_t size) { + char *buffer = buffer_; size_t bytes_read = 0; while (bytes_read < size) @@ -700,8 +680,9 @@ full_read (int fd, char *buffer, size_t size) /* Calls write(), passing FD, BUFFER, and SIZE, repeating as necessary to deal with interrupted calls. */ static int -full_write (int fd, const char *buffer, size_t size) +full_write (int fd, const void *buffer_, size_t size) { + const char *buffer = buffer_; size_t bytes_written = 0; while (bytes_written < size) @@ -716,6 +697,7 @@ full_write (int fd, const char *buffer, size_t size) return bytes_written; } + /* Registers our exit handler with atexit() if it has not already been registered. */ static void @@ -729,6 +711,8 @@ register_atexit (void) } } + + /* atexit() handler that closes and deletes our temporary files. */ static void @@ -738,9 +722,9 @@ exit_handler (void) casefile_destroy (casefiles); } +#include #include #include "command.h" -#include "random.h" #include "lexer.h" static void test_casefile (int pattern, size_t value_cnt, size_t case_cnt); @@ -775,7 +759,7 @@ cmd_debug_casefile (void) if (token != '.') return lex_end_of_command (); - for (pattern = 0; pattern < 5; pattern++) + for (pattern = 0; pattern < 6; pattern++) { const size_t *size; @@ -795,23 +779,26 @@ cmd_debug_casefile (void) static void test_casefile (int pattern, size_t value_cnt, size_t case_cnt) { - int zero = 0; struct casefile *cf; struct casereader *r1, *r2; struct ccase c; - struct rng *rng; + gsl_rng *rng; size_t i, j; - rng = rng_create (); - rng_seed (rng, &zero, sizeof zero); + rng = gsl_rng_alloc (gsl_rng_mt19937); cf = casefile_create (value_cnt); + if (pattern == 5) + casefile_to_disk (cf); for (i = 0; i < case_cnt; i++) write_random_case (cf, i); + if (pattern == 5) + casefile_sleep (cf); r1 = casefile_get_reader (cf); r2 = casefile_get_reader (cf); switch (pattern) { case 0: + case 5: for (i = 0; i < case_cnt; i++) { read_and_verify_random_case (cf, r1, i); @@ -830,8 +817,8 @@ test_casefile (int pattern, size_t value_cnt, size_t case_cnt) for (i = j = 0; i < case_cnt; i++) { read_and_verify_random_case (cf, r1, i); - if (rng_get_int (rng) % pattern == 0) - read_and_verify_random_case (cf, r2, j++); + if (gsl_rng_get (rng) % pattern == 0) + read_and_verify_random_case (cf, r2, j++); if (i == case_cnt / 2) casefile_to_disk (cf); } @@ -870,7 +857,7 @@ test_casefile (int pattern, size_t value_cnt, size_t case_cnt) casereader_destroy (r1); } casefile_destroy (cf); - rng_destroy (rng); + gsl_rng_free (rng); } static void