From 1d57a8b4c556e227cd562dcfa56c8cbce79f73a8 Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Thu, 29 Jul 2010 21:16:06 -0700 Subject: [PATCH 1/1] temp-file: Rename "ext-array" (for "external array"). I want to introduce a new source module for general creation of temporary files and this module's name conflicts. --- src/data/case-tmpfile.c | 12 +- src/libpspp/automake.mk | 4 +- src/libpspp/ext-array.c | 165 ++++++++++++++++++++++ src/libpspp/{temp-file.h => ext-array.h} | 20 +-- src/libpspp/sparse-xarray.c | 40 +++--- src/libpspp/temp-file.c | 167 ----------------------- tests/automake.mk | 2 +- 7 files changed, 204 insertions(+), 206 deletions(-) create mode 100644 src/libpspp/ext-array.c rename src/libpspp/{temp-file.h => ext-array.h} (65%) delete mode 100644 src/libpspp/temp-file.c diff --git a/src/data/case-tmpfile.c b/src/data/case-tmpfile.c index 2b47d6dd26..b2444b9bc5 100644 --- a/src/data/case-tmpfile.c +++ b/src/data/case-tmpfile.c @@ -24,7 +24,7 @@ #include #include -#include +#include #include "error.h" #include "xalloc.h" @@ -36,7 +36,7 @@ struct case_tmpfile struct caseproto *proto; /* Format of cases in the tmpfile. */ size_t case_size; /* Number of bytes per case. */ size_t *offsets; /* Offset to each value. */ - struct temp_file *temp_file; /* Temporary file. */ + struct ext_array *ext_array; /* Temporary file. */ }; /* Returns the number of bytes needed to store a value with the @@ -72,7 +72,7 @@ case_tmpfile_create (const struct caseproto *proto) ctf = xmalloc (sizeof *ctf); ctf->taint = taint_create (); - ctf->temp_file = temp_file_create (); + ctf->ext_array = ext_array_create (); ctf->proto = caseproto_ref (proto); ctf->case_size = 0; n_values = caseproto_get_n_widths (proto); @@ -97,7 +97,7 @@ case_tmpfile_destroy (struct case_tmpfile *ctf) if (ctf != NULL) { struct taint *taint = ctf->taint; - temp_file_destroy (ctf->temp_file); + ext_array_destroy (ctf->ext_array); caseproto_unref (ctf->proto); free (ctf->offsets); free (ctf); @@ -149,7 +149,7 @@ case_tmpfile_get_values (const struct case_tmpfile *ctf, { int width = caseproto_get_width (ctf->proto, i); if (width != -1 - && !temp_file_read (ctf->temp_file, case_offset + ctf->offsets[i], + && !ext_array_read (ctf->ext_array, case_offset + ctf->offsets[i], width_to_n_bytes (width), value_to_data (&values[i], width))) return false; @@ -194,7 +194,7 @@ case_tmpfile_put_values (struct case_tmpfile *ctf, { int width = caseproto_get_width (ctf->proto, i); if (width != -1 - && !temp_file_write (ctf->temp_file, case_offset + ctf->offsets[i], + && !ext_array_write (ctf->ext_array, case_offset + ctf->offsets[i], width_to_n_bytes (width), value_to_data (values++, width))) return false; diff --git a/src/libpspp/automake.mk b/src/libpspp/automake.mk index e9a5e6093f..5cf669553b 100644 --- a/src/libpspp/automake.mk +++ b/src/libpspp/automake.mk @@ -20,6 +20,8 @@ src_libpspp_libpspp_la_SOURCES = \ src/libpspp/copyleft.h \ src/libpspp/deque.c \ src/libpspp/deque.h \ + src/libpspp/ext-array.c \ + src/libpspp/ext-array.h \ src/libpspp/float-format.c \ src/libpspp/float-format.h \ src/libpspp/freaderror.c \ @@ -82,8 +84,6 @@ src_libpspp_libpspp_la_SOURCES = \ src/libpspp/str.h \ src/libpspp/taint.c \ src/libpspp/taint.h \ - src/libpspp/temp-file.c \ - src/libpspp/temp-file.h \ src/libpspp/tower.c \ src/libpspp/tower.h \ src/libpspp/version.h \ diff --git a/src/libpspp/ext-array.c b/src/libpspp/ext-array.c new file mode 100644 index 0000000000..df3b589fe0 --- /dev/null +++ b/src/libpspp/ext-array.c @@ -0,0 +1,165 @@ +/* PSPP - a program for statistical analysis. + Copyright (C) 2007, 2009, 2010 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +/* An interface to an array of octets that is stored on disk as a temporary + file. */ + +#include + +#include + +#include +#include +#include + +#include +#include + +#include "error.h" +#include "xalloc.h" + +#include "gettext.h" +#define _(msgid) gettext (msgid) + +struct ext_array + { + FILE *file; /* Underlying file. */ + + /* Current byte offset in file. We track this manually, + instead of using ftello, because in glibc ftello flushes + the stream buffer, making the common case of sequential + access to cases unreasonably slow. */ + off_t position; + }; + +/* Creates and returns a new external array. */ +struct ext_array * +ext_array_create (void) +{ + struct ext_array *ea = xmalloc (sizeof *ea); + ea->file = tmpfile (); + if (ea->file == NULL) + error (0, errno, _("failed to create temporary file")); + ea->position = 0; + return ea; +} + +/* Closes and destroys external array EA. Returns true if I/O on EA always + succeeded, false if an I/O error occurred at some point. */ +bool +ext_array_destroy (struct ext_array *ea) +{ + bool ok = true; + if (ea != NULL) + { + ok = !ext_array_error (ea); + if (ea->file != NULL) + fclose (ea->file); + free (ea); + } + return ok; +} + +/* Seeks EA's underlying file to the start of `union value' + VALUE_IDX within case CASE_IDX. + Returns true if the seek is successful and EA is not + otherwise tainted, false otherwise. */ +static bool +do_seek (const struct ext_array *ea_, off_t offset) +{ + struct ext_array *ea = CONST_CAST (struct ext_array *, ea_); + + if (!ext_array_error (ea)) + { + if (ea->position == offset) + return true; + else if (fseeko (ea->file, offset, SEEK_SET) == 0) + { + ea->position = offset; + return true; + } + else + error (0, errno, _("seeking in temporary file")); + } + + return false; +} + +/* Reads BYTES bytes from EA's underlying file into BUFFER. + EA must not be tainted upon entry into this function. + Returns true if successful, false upon an I/O error (in which + case EA is marked tainted). */ +static bool +do_read (const struct ext_array *ea_, void *buffer, size_t bytes) +{ + struct ext_array *ea = CONST_CAST (struct ext_array *, ea_); + + assert (!ext_array_error (ea)); + if (bytes > 0 && fread (buffer, bytes, 1, ea->file) != 1) + { + if (ferror (ea->file)) + error (0, errno, _("reading temporary file")); + else if (feof (ea->file)) + error (0, 0, _("unexpected end of file reading temporary file")); + else + NOT_REACHED (); + return false; + } + ea->position += bytes; + return true; +} + +/* Writes BYTES bytes from BUFFER into EA's underlying file. + EA must not be tainted upon entry into this function. + Returns true if successful, false upon an I/O error (in which + case EA is marked tainted). */ +static bool +do_write (struct ext_array *ea, const void *buffer, size_t bytes) +{ + assert (!ext_array_error (ea)); + if (bytes > 0 && fwrite (buffer, bytes, 1, ea->file) != 1) + { + error (0, errno, _("writing to temporary file")); + return false; + } + ea->position += bytes; + return true; +} + +/* Reads N bytes from EA at byte offset OFFSET into DATA. + Returns true if successful, false on failure. */ +bool +ext_array_read (const struct ext_array *ea, off_t offset, size_t n, void *data) +{ + return do_seek (ea, offset) && do_read (ea, data, n); +} + +/* Writes the N bytes in DATA to EA at byte offset OFFSET. + Returns true if successful, false on failure. */ +bool +ext_array_write (struct ext_array *ea, off_t offset, size_t n, + const void *data) +{ + return do_seek (ea, offset) && do_write (ea, data, n); +} + +/* Returns true if an error has occurred in I/O on EA, + false if no error has been detected. */ +bool +ext_array_error (const struct ext_array *ea) +{ + return ea->file == NULL || ferror (ea->file) || feof (ea->file); +} diff --git a/src/libpspp/temp-file.h b/src/libpspp/ext-array.h similarity index 65% rename from src/libpspp/temp-file.h rename to src/libpspp/ext-array.h index 5965d544ae..0b82483f98 100644 --- a/src/libpspp/temp-file.h +++ b/src/libpspp/ext-array.h @@ -14,20 +14,20 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/* A interface to allow a temporary file to be treated as an - array of data. */ +/* An interface to an array of octets that is stored on disk as a temporary + file. */ -#ifndef LIBPSPP_TEMP_FILE_H -#define LIBPSPP_TEMP_FILE_H 1 +#ifndef LIBPSPP_EXT_ARRAY_H +#define LIBPSPP_EXT_ARRAY_H 1 #include #include -struct temp_file *temp_file_create (void); -bool temp_file_destroy (struct temp_file *); -bool temp_file_read (const struct temp_file *, off_t offset, size_t n, void *); -bool temp_file_write (struct temp_file *, off_t offset, size_t n, +struct ext_array *ext_array_create (void); +bool ext_array_destroy (struct ext_array *); +bool ext_array_read (const struct ext_array *, off_t offset, size_t n, void *); +bool ext_array_write (struct ext_array *, off_t offset, size_t n, const void *); -bool temp_file_error (const struct temp_file *); +bool ext_array_error (const struct ext_array *); -#endif /* libpspp/temp-file.h */ +#endif /* libpspp/ext-array.h */ diff --git a/src/libpspp/sparse-xarray.c b/src/libpspp/sparse-xarray.c index 7480f7c266..69c2ef28a7 100644 --- a/src/libpspp/sparse-xarray.c +++ b/src/libpspp/sparse-xarray.c @@ -24,10 +24,10 @@ #include #include +#include #include #include #include -#include #include "md4.h" #include "minmax.h" @@ -40,7 +40,7 @@ struct sparse_xarray uint8_t *default_row; /* Defaults for unwritten rows. */ unsigned long int max_memory_rows; /* Max rows before dumping to disk. */ struct sparse_array *memory; /* Backing, if stored in memory. */ - struct temp_file *disk; /* Backing, if stored on disk. */ + struct ext_array *disk; /* Backing, if stored on disk. */ struct range_set *disk_rows; /* Allocated rows, if on disk. */ }; @@ -103,7 +103,7 @@ sparse_xarray_clone (const struct sparse_xarray *old) const struct range_set_node *node; void *tmp = xmalloc (old->n_bytes); - new->disk = temp_file_create (); + new->disk = ext_array_create (); new->disk_rows = range_set_clone (old->disk_rows, NULL); for (node = range_set_first (old->disk_rows); node != NULL; node = range_set_next (old->disk_rows, node)) @@ -115,8 +115,8 @@ sparse_xarray_clone (const struct sparse_xarray *old) for (idx = start; idx < end; idx++) { off_t offset = (off_t) idx * old->n_bytes; - if (!temp_file_read (old->disk, offset, old->n_bytes, tmp) - || !temp_file_write (new->disk, offset, old->n_bytes, tmp)) + if (!ext_array_read (old->disk, offset, old->n_bytes, tmp) + || !ext_array_write (new->disk, offset, old->n_bytes, tmp)) { free (tmp); sparse_xarray_destroy (new); @@ -151,7 +151,7 @@ sparse_xarray_destroy (struct sparse_xarray *sx) free (*row); sparse_array_destroy (sx->memory); } - temp_file_destroy (sx->disk); + ext_array_destroy (sx->disk); range_set_destroy (sx->disk_rows); free (sx); } @@ -192,16 +192,16 @@ dump_sparse_xarray_to_disk (struct sparse_xarray *sx) assert (sx->memory != NULL); assert (sx->disk == NULL); - sx->disk = temp_file_create (); + sx->disk = ext_array_create (); sx->disk_rows = range_set_create (); for (row = sparse_array_first (sx->memory, &idx); row != NULL; row = sparse_array_next (sx->memory, idx, &idx)) { - if (!temp_file_write (sx->disk, (off_t) idx * sx->n_bytes, sx->n_bytes, + if (!ext_array_write (sx->disk, (off_t) idx * sx->n_bytes, sx->n_bytes, *row)) { - temp_file_destroy (sx->disk); + ext_array_destroy (sx->disk); sx->disk = NULL; range_set_destroy (sx->disk_rows); sx->disk_rows = NULL; @@ -246,7 +246,7 @@ sparse_xarray_read (const struct sparse_xarray *sx, unsigned long int row, else { if (range_set_contains (sx->disk_rows, row)) - return temp_file_read (sx->disk, (off_t) row * sx->n_bytes + start, + return ext_array_read (sx->disk, (off_t) row * sx->n_bytes + start, n, data); } @@ -261,13 +261,13 @@ write_disk_row (struct sparse_xarray *sx, unsigned long int row, { off_t ofs = (off_t) row * sx->n_bytes; if (range_set_contains (sx->disk_rows, row)) - return temp_file_write (sx->disk, ofs + start, n, data); + return ext_array_write (sx->disk, ofs + start, n, data); else { range_set_insert (sx->disk_rows, row, 1); - return (temp_file_write (sx->disk, ofs, start, sx->default_row) - && temp_file_write (sx->disk, ofs + start, n, data) - && temp_file_write (sx->disk, ofs + start + n, + return (ext_array_write (sx->disk, ofs, start, sx->default_row) + && ext_array_write (sx->disk, ofs + start, n, data) + && ext_array_write (sx->disk, ofs + start + n, sx->n_bytes - start - n, sx->default_row + start + n)); } @@ -346,12 +346,12 @@ sparse_xarray_write_columns (struct sparse_xarray *sx, size_t start, for (row = start_row; row < end_row; row++) { off_t offset = (off_t) row * sx->n_bytes; - if (!temp_file_write (sx->disk, offset + start, n, data)) + if (!ext_array_write (sx->disk, offset + start, n, data)) break; } } - if (temp_file_error (sx->disk)) + if (ext_array_error (sx->disk)) return false; } return true; @@ -392,7 +392,7 @@ get_row (const struct sparse_xarray *sx, unsigned long int idx, uint8_t **p = sparse_array_get (sx->memory, idx); return *p; } - else if (temp_file_read (sx->disk, (off_t) idx * sx->n_bytes, + else if (ext_array_read (sx->disk, (off_t) idx * sx->n_bytes, sx->n_bytes, buffer)) return buffer; else @@ -456,10 +456,10 @@ sparse_xarray_copy (const struct sparse_xarray *sx, struct sparse_xarray *dx, for (row = start; row < end; row++) { off_t offset = (off_t) row * sx->n_bytes; - success = (temp_file_read (sx->disk, offset, sx->n_bytes, + success = (ext_array_read (sx->disk, offset, sx->n_bytes, tmp) && cb (tmp, tmp, aux) - && temp_file_write (dx->disk, offset, + && ext_array_write (dx->disk, offset, dx->n_bytes, tmp)); if (!success) break; @@ -597,7 +597,7 @@ sparse_xarray_model_checker_hash (const struct sparse_xarray *sx, for (idx = start; idx < end; idx++) { off_t offset = (off_t) idx * sx->n_bytes; - if (!temp_file_read (sx->disk, offset, sx->n_bytes, tmp)) + if (!ext_array_read (sx->disk, offset, sx->n_bytes, tmp)) NOT_REACHED (); md4_process_bytes (&idx, sizeof idx, &ctx); md4_process_bytes (tmp, sx->n_bytes, &ctx); diff --git a/src/libpspp/temp-file.c b/src/libpspp/temp-file.c deleted file mode 100644 index 554a6d7d5f..0000000000 --- a/src/libpspp/temp-file.c +++ /dev/null @@ -1,167 +0,0 @@ -/* PSPP - a program for statistical analysis. - Copyright (C) 2007, 2009, 2010 Free Software Foundation, Inc. - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . */ - -/* A interface to allow a temporary file to be treated as an - array of data. */ - -#include - -#include - -#include -#include -#include - -#include -#include - -#include "error.h" -#include "xalloc.h" - -#include "gettext.h" -#define _(msgid) gettext (msgid) - -struct temp_file - { - FILE *file; /* Underlying file. */ - - /* Current byte offset in file. We track this manually, - instead of using ftello, because in glibc ftello flushes - the stream buffer, making the common case of sequential - access to cases unreasonably slow. */ - off_t position; - }; - -/* Creates and returns a new temporary file. The temporary file - will be automatically deleted when the process exits. */ -struct temp_file * -temp_file_create (void) -{ - struct temp_file *tf = xmalloc (sizeof *tf); - tf->file = tmpfile (); - if (tf->file == NULL) - error (0, errno, _("failed to create temporary file")); - tf->position = 0; - return tf; -} - -/* Closes and destroys temporary file TF. Returns true if I/O on - TF always succeeded, false if an I/O error occurred at some - point. */ -bool -temp_file_destroy (struct temp_file *tf) -{ - bool ok = true; - if (tf != NULL) - { - ok = !temp_file_error (tf); - if (tf->file != NULL) - fclose (tf->file); - free (tf); - } - return ok; -} - -/* Seeks TF's underlying file to the start of `union value' - VALUE_IDX within case CASE_IDX. - Returns true if the seek is successful and TF is not - otherwise tainted, false otherwise. */ -static bool -do_seek (const struct temp_file *tf_, off_t offset) -{ - struct temp_file *tf = CONST_CAST (struct temp_file *, tf_); - - if (!temp_file_error (tf)) - { - if (tf->position == offset) - return true; - else if (fseeko (tf->file, offset, SEEK_SET) == 0) - { - tf->position = offset; - return true; - } - else - error (0, errno, _("seeking in temporary file")); - } - - return false; -} - -/* Reads BYTES bytes from TF's underlying file into BUFFER. - TF must not be tainted upon entry into this function. - Returns true if successful, false upon an I/O error (in which - case TF is marked tainted). */ -static bool -do_read (const struct temp_file *tf_, void *buffer, size_t bytes) -{ - struct temp_file *tf = CONST_CAST (struct temp_file *, tf_); - - assert (!temp_file_error (tf)); - if (bytes > 0 && fread (buffer, bytes, 1, tf->file) != 1) - { - if (ferror (tf->file)) - error (0, errno, _("reading temporary file")); - else if (feof (tf->file)) - error (0, 0, _("unexpected end of file reading temporary file")); - else - NOT_REACHED (); - return false; - } - tf->position += bytes; - return true; -} - -/* Writes BYTES bytes from BUFFER into TF's underlying file. - TF must not be tainted upon entry into this function. - Returns true if successful, false upon an I/O error (in which - case TF is marked tainted). */ -static bool -do_write (struct temp_file *tf, const void *buffer, size_t bytes) -{ - assert (!temp_file_error (tf)); - if (bytes > 0 && fwrite (buffer, bytes, 1, tf->file) != 1) - { - error (0, errno, _("writing to temporary file")); - return false; - } - tf->position += bytes; - return true; -} - -/* Reads N bytes from TF at byte offset OFFSET into DATA. - Returns true if successful, false on failure. */ -bool -temp_file_read (const struct temp_file *tf, off_t offset, size_t n, void *data) -{ - return do_seek (tf, offset) && do_read (tf, data, n); -} - -/* Writes the N bytes in DATA to TF at byte offset OFFSET. - Returns true if successful, false on failure. */ -bool -temp_file_write (struct temp_file *tf, off_t offset, size_t n, - const void *data) -{ - return do_seek (tf, offset) && do_write (tf, data, n); -} - -/* Returns true if an error has occurred in I/O on TF, - false if no error has been detected. */ -bool -temp_file_error (const struct temp_file *tf) -{ - return tf->file == NULL || ferror (tf->file) || feof (tf->file); -} diff --git a/tests/automake.mk b/tests/automake.mk index 7c7c004140..46524f9aa2 100644 --- a/tests/automake.mk +++ b/tests/automake.mk @@ -328,13 +328,13 @@ tests_libpspp_sparse_xarray_test_SOURCES = \ src/libpspp/argv-parser.c \ src/libpspp/bt.c \ src/libpspp/deque.c \ + src/libpspp/ext-array.c \ src/libpspp/model-checker.c \ src/libpspp/range-set.c \ src/libpspp/sparse-array.c \ src/libpspp/sparse-xarray.c \ src/libpspp/str.c \ src/libpspp/pool.c \ - src/libpspp/temp-file.c \ tests/libpspp/sparse-xarray-test.c tests_libpspp_sparse_xarray_test_LDADD = gl/libgl.la $(LIBINTL) tests_libpspp_sparse_xarray_test_CPPFLAGS = $(AM_CPPFLAGS) -DASSERT_LEVEL=10 -- 2.30.2