UnixWorld Online: Tutorial Article No. 011 Listings Listing 1. Pseudo-code implementation of restart algorithms. A. The client functions void newdownload(char* filename) { // The client UI will call this function if user // wants to download a file from the beginning, // not restart an aborted file transfer procedure // long tbt = 0; // total bytes transferred char buf[2048]; // buffer long bt; // bytes transferred in // a single block int fd; // local file descriptor fd = _open(filename, O_WRONLY); // Create a new local file bt = svr_read(&buf); // returns buf size while (bt > 0) { if (isrestartmarker(buf)){ // if buf is a restart marker updatelogservertimestamp(filename,buf); // then update Log file } else { tbt = tbt + bt; // increment total bytes transferred updatelogbytesize(filename, tbt); _write(fd, buf, sizeof(buf)); }; bt = svr_read(&buf); }; _close(fd); // close local file } void restartdownload(char* filename) { // The client UI will call this function if user // wants to restart aborted file transfer process // long tbt = 0; // total bytes transferred char buf[2048]; // buffer long bt; // bytes transferred in a single block int fd; // local file descriptor TIMESTAMP sts; // last recorded server timestamp in Log TIMESTAMP cts; // last recorded client timestamp in Log int ret; // return code for error recovery // Check if the local file size matches that in Transfer Log // tbt = getlogbytesize(filename); sts = getlogservertimestamp(filename); cts = getlogclienttimestamp(filename); fd = _open(filename, O_APPEND); // Create a new local file if (tbt! = _filelength(fd) || cts! = getclientfiletimetstamp(filename)) { // local file has changed // since download _close(fd); // abort restart procedure return(); }; ret = svr_restart(filename, // ask server to start tbt, // (RPC Call) sts); if (ret == -1) goto shutdown; // error recovery bt = svr_read(&buf); while (bt > 0) { // if buf is a restart marker // then update Log file if (isrestartmarker(buf)) { updatelogtimestamp(filename, buf); } else { tbt = tbt + bt; // increment total bytes // transferred updatelogbytesize(filename, tbt); _write(fd, buf, sizeof(buf)); }; bt = svr_read(&buf); }; shutdown: close(fd); // close local file } void updatelogservertimestamp(char* filename,char* buf) { int TSLENGTH = 8; // Timestamp length int fd; // file descriptor of log file LOGSTRUCT ls = NULL; char t[8]; fd = _open(filename, O_RDWR); while (read(fd, ls, sizeof(LOGSTRUCT))) { if (strcmp(ls.filename, filename) == 0) { // I found the Log record! strncpy(t, ls.filename, TSLENGTH); // get the timestamp out of buf ls.rt = (TIMESTAMP)t; // cast into timestamp _write(fd, ls); exit; }; }; _close(fd); } void updatelogclienttimestamp(char* filename, char* buf) { int TSLENGTH = 8; // Timestamp length int fd; // file descriptor of log file LOGSTRUCT ls = NULL; char t[8]; fd = _open(filename, O_RDWR); while (read(fd, ls, sizeof(LOGSTRUCT))) { if (strcmp(ls.filename, filename) == 0) { // I found the Log record! strncpy(t, ls.filename, TSLENGTH); // get the timestamp out of buf ls.ct = (TIMESTAMP)t; // cast into timestamp _write(fd, ls); exit; }; }; _close(fd); } updatelogbytesize(char* filename, long tbt) { int fd; // file descriptor of log file LOGSTRUCT ls = NULL; fd = _open(filename, O_RDWR); while (read(fd, ls, sizeof(LOGSTRUCT))) { if (strcmp(ls.filename, filename) == 0) { // I found the Log record! ls.bytestransferred = tbt; _write(fd, ls); exit; }; }; _close(fd); } TIMESTAMP getlogservertimestamp(char* filename) { int fd; // file descriptor of log file LOGSTRUCT ls = NULL; fd = _open(filename, O_RDWR); while (read(fd, ls, sizeof(LOGSTRUCT))) { if (strcmp(ls.filename, filename) == 0) { // I found the Log record! return ls.rt; // return timestamp }; }; _close(fd); return NULL; } TIMESTAMP getlogclienttimestamp(char* filename) { int fd; // file descriptor of log file LOGSTRUCT ls = NULL; fd = _open(filename, O_RDWR); while (read(fd, ls, sizeof(LOGSTRUCT))) { if (strcmp(ls.filename, filename) == 0) { // I found the Log record! return ls.ct; // return timestamp }; }; _close(fd); return NULL; } long getlogbytesize(char *filename) { int fd; // file descriptor of log file LOGSTRUCT ls = NULL; fd = _open(filename, O_RDONLY); while (read(fd, ls, sizeof(LOGSTRUCT))) { if (strcmp(ls.filename, filename) == 0) { // I found the Log record! return ls.bytestransferred; }; }; _close(fd); return 0; } TIMESTAMP getclientfiletimestamp(char *filename) { TIMESTAMP t = NULL; int fd; // file descriptor of log file char buf[2048]; fd = _open(filename, O_RDONLY); if (fd>0) { t = _fstat(fd, &buffer); _close(fd); }; return t.st_time; } B. The server functions static LOGSTRUCT ls; static int fd; static int tbt; // total bytes transferred // during this session static int rc; // counter for restart marker intervals #define RESTART_INTERVAL 100000 int svr_restart(char* filename, long tbt, TIMESTAMP ts) { int c = 2048; char buf[2048]; struct _stat buffer; fd = _open(filename, O_RDONLY); _fstat(fd, &buffer); if (buffer.st_time! = ts) return -1; // file has changed! while (tbt > 0) { // Otherwise, move file pointer // by tbt bytes if (tbt < c) c = tbt; read(fd, buf, c); tbt = tbt - c; }; } int svr_read(char* filename,char **buf) { int c = 2048, n; struct _stat buffer; strcpy(ls.filename, filename); if (rc > RESTART_INTERVAL) { // Send Restart Marker rc = 0; // every 100K bytes ls.bytestransferred = tbt; _fstat(fd, &buffer); ls.ts = buffer.st_time; buf = (char **)ls; } else { // else just move the n = _read(fd, *buf, c); // data down the pipe tbt = tbt + n; rc = rc + n; }; if (n == 0) _close(fd); // close the file when EOF return(strlen(*buf)); }; ---------------------------------------------------------------------------- Copyright © 1995 The McGraw-Hill Companies, Inc. All Rights Reserved. Edited by Becca Thomas / Online Editor / UnixWorld Online / editor@unixworld.com [Go to Contents] [Search Editorial] Last Modified: Sunday, 21-Jan-96 06:09:50 PST