Skip to content

Commit

Permalink
Refined fwrite error messages, #1664
Browse files Browse the repository at this point in the history
  • Loading branch information
mattdowle committed Nov 4, 2016
1 parent 1a4263f commit 28502a9
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 22 deletions.
10 changes: 7 additions & 3 deletions R/fwrite.R
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,15 @@ fwrite <- function(x, file="", append=FALSE, quote="auto",
col.names = FALSE # test 1658.16 checks this
if (!..turbo) warning("The ..turbo=FALSE option will be removed in future. Please report any problems with ..turbo=TRUE.")
if (identical(quote,"auto")) quote=NA # logical NA
if (verbose || file=="") old=setDTthreads(1) # console output isn't thread safe
if (file=="") showProgress=FALSE
if (file=="") {
# console output (Rprintf) isn't thread safe.
# Perhaps more so on Windows (as experienced) than Linux
old=setDTthreads(1)
on.exit(setDTthreads(old))
showProgress=FALSE
}
.Call(Cwritefile, x, file, sep, eol, na, dec, quote, qmethod=="escape", append,
row.names, col.names, showProgress, verbose, ..turbo)
if (verbose) setDTthreads(old)
invisible()
}

Expand Down
24 changes: 14 additions & 10 deletions inst/tests/tests.Rraw
Original file line number Diff line number Diff line change
Expand Up @@ -9535,24 +9535,28 @@ test(1734.6, capture.output(fwrite(DF,row.names=TRUE,quote=FALSE)),
test(1734.7, capture.output(fwrite(DF,row.names=TRUE,quote=TRUE)),
capture.output(write.csv(DF)))

# fwrite showProgress test. Turned off as too long for CRAN.
# fwrite showProgress test. Turned off as too long/big for CRAN.
if (FALSE) {
N = 6e8 # apx 6GB
DT = data.table(C1=sample(100000,N,replace=TRUE), C2=sample(paste0(LETTERS,LETTERS,LETTERS), N, replace=TRUE))
gc()
setDTthreads(1) # to slow it down
system.time(fwrite(DT, "/tmp/test.txt"))
system("ls -lh /tmp/test.txt")

f = "/dev/shm/test.txt" # or "/tmp/test.txt"
setDTthreads(1)
system.time(fwrite(DT, f))
file.info(f)$size/1024^3
unlink(f)
# ensure progress meter itself isn't taking time; e.g. too many calls to time() or clock()
system.time(fwrite(DT, "/tmp/test.txt", showProgress=FALSE))

system.time(fwrite(DT, f, showProgress=FALSE))
setDTthreads(2) # make sure it works with several threads
system.time(fwrite(DT, "/tmp/test.txt"))
system.time(fwrite(DT, f)) # no need to unlink(f), it'll overwrite
setDTthreads(4)
system.time(fwrite(DT, "/tmp/test.txt"))
system.time(fwrite(DT, f))
setDTthreads(0)
system.time(fwrite(DT, "/tmp/test.txt"))
system.time(fwrite(DT, f))
f2 = "/dev/shm/test2.txt"
system.time(fwrite(DT, f2)) # test 'No space left on device'
unlink(f)
unlink(f2)
}


Expand Down
19 changes: 10 additions & 9 deletions src/fwrite.c
Original file line number Diff line number Diff line change
Expand Up @@ -344,9 +344,9 @@ SEXP writefile(SEXP list_of_columns,
if (f == -1) {
char *err = strerror(errno);
if( access( filename, F_OK ) != -1 )
error("'%s'. Failed to open existing file for writing. Do you have write permission to it? Is this Windows and does another process such as Excel have it open? File: %s", err, filename);
error("%s: '%s'. Failed to open existing file for writing. Do you have write permission to it? Is this Windows and does another process such as Excel have it open?", err, filename);
else
error("'%s'. Unable to create new file for writing (it does not exist already). Do you have permission to write here and is there space on the disk? File: %s", err, filename);
error("%s: '%s'. Unable to create new file for writing (it does not exist already). Do you have permission to write here, is there space on the disk and does the path exist?", err, filename);
}
}
int true_false;
Expand Down Expand Up @@ -431,14 +431,14 @@ SEXP writefile(SEXP list_of_columns,
memcpy(ch, row_sep, row_sep_len); // replace it with the newline
ch += row_sep_len;
if (f==-1) { *ch='\0'; Rprintf(buffer); }
else if (WRITE(f, buffer, (int)(ch-buffer))==-1) { close(f); error("Error writing to file: %s", filename); }
else if (WRITE(f, buffer, (int)(ch-buffer))==-1) { close(f); error("%s: '%s'", strerror(errno), filename); }
free(buffer);
}
}
if (verbose) Rprintf("done in %.3fs\n", 1.0*(clock()-t0)/CLOCKS_PER_SEC);
if (nrows == 0) {
if (verbose) Rprintf("No data rows present (nrow==0)\n");
if (f!=-1 && CLOSE(f)) error("Error closing file: %s", filename);
if (f!=-1 && CLOSE(f)) error("%s: '%s'", strerror(errno), filename);
return(R_NilValue);
}

Expand Down Expand Up @@ -618,7 +618,8 @@ SEXP writefile(SEXP list_of_columns,
// showProgress=FALSE until this can be fixed or removed.
int eta = (int)((nrows-upp)*(((double)(now-start))/upp));
if (hasPrinted || eta >= 2) {
Rprintf("\rWritten %.1f%% of %d rows in %d secs using %d thread%s. ETA %d secs.",
if (verbose && !hasPrinted) Rprintf("\n");
Rprintf("\rWritten %.1f%% of %d rows in %d secs using %d thread%s. ETA %d secs. ",
(100.0*upp)/nrows, nrows, (int)(now-start), nth, nth==1?"":"s", eta);
R_FlushConsole(); // for Windows
nexttime = now+1;
Expand Down Expand Up @@ -655,7 +656,7 @@ SEXP writefile(SEXP list_of_columns,
R_FlushConsole(); // for Windows
}
if (f!=-1 && CLOSE(f) && !failed)
error("Completed writing ok but error closing file '%s': %s", filename, strerror(errno));
error("%s: '%s'", strerror(errno), filename);
// quoted '%s' in case of trailing spaces in the filename
// If a write failed, the line above tries close() to clean up, but that might fail as well. The
// && !failed is to not report the error as just 'closing file' but the next line for more detail
Expand All @@ -664,11 +665,11 @@ SEXP writefile(SEXP list_of_columns,
if (failed_reason==-1) {
error("One or more threads failed to alloc or realloc their private buffer. Out of memory.\n");
} else {
error("Failed write to '%s': %s. Out of disk space is most likely especially if /dev/shm or /tmp since they have smaller limits. Or perhaps network issue if NFS. Your operating system reported that it opened the file ok in write mode but perhaps it only checks permissions when actually writing some data.", filename, strerror(failed_reason));
error("%s: '%s'", strerror(failed_reason), filename);
}
}
if (verbose) Rprintf("all %d threads done\n", nth); // TO DO: report elapsed time since (clock()-t0)/NTH is only estimate
return(R_NilValue); // must always return SEXP from C level otherwise hang on Windows
if (verbose) Rprintf("done (nth=%d)\n", nth);
return(R_NilValue);
}


0 comments on commit 28502a9

Please sign in to comment.