$treeview $search $mathjax $extrastylesheet
librsync
2.0.2
$projectbrief
|
$projectbrief
|
$searchbox |
00001 /*= -*- c-basic-offset: 4; indent-tabs-mode: nil; -*- 00002 * 00003 * librsync -- dynamic caching and delta update in HTTP 00004 * 00005 * Copyright (C) 2000, 2001 by Martin Pool <mbp@sourcefrog.net> 00006 * 00007 * This program is free software; you can redistribute it and/or modify 00008 * it under the terms of the GNU Lesser General Public License as published by 00009 * the Free Software Foundation; either version 2.1 of the License, or 00010 * (at your option) any later version. 00011 * 00012 * This program is distributed in the hope that it will be useful, 00013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00015 * GNU Lesser General Public License for more details. 00016 * 00017 * You should have received a copy of the GNU Lesser General Public License 00018 * along with this program; if not, write to the Free Software 00019 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 00020 */ 00021 00022 /*= 00023 | Where a calculator on the ENIAC is 00024 | equpped with 18,000 vaccuum tubes and 00025 | weighs 30 tons, computers in the 00026 | future may have only 1,000 vaccuum 00027 | tubes and perhaps weigh 1 1/2 00028 | tons. 00029 | -- Popular Mechanics, March 1949 00030 */ 00031 00032 /** \file tube.c A somewhat elastic but fairly small buffer for data passing 00033 * through a stream. 00034 * 00035 * In most cases the iter can adjust to send just as much data will fit. In 00036 * some cases that would be too complicated, because it has to transmit an 00037 * integer or something similar. So in that case we stick whatever won't fit 00038 * into a small buffer. 00039 * 00040 * A tube can contain some literal data to go out (typically command bytes), 00041 * and also an instruction to copy data from the stream's input or from some 00042 * other location. Both literal data and a copy command can be queued at the 00043 * same time, but only in that order and at most one of each. 00044 * 00045 * \todo As an optimization, write it directly to the stream if possible. But 00046 * for simplicity don't do that yet. 00047 * 00048 * \todo I think our current copy code will lock up if the application only 00049 * ever calls us with either input or output buffers, and not both. So I guess 00050 * in that case we might need to copy into some temporary buffer space, and 00051 * then back out again later. */ 00052 00053 #include "config.h" 00054 00055 #include <assert.h> 00056 #include <stdlib.h> 00057 #include <string.h> 00058 #include <stdio.h> 00059 00060 #include "librsync.h" 00061 #include "trace.h" 00062 #include "util.h" 00063 #include "job.h" 00064 #include "stream.h" 00065 00066 static void rs_tube_catchup_write(rs_job_t *job) 00067 { 00068 rs_buffers_t *stream = job->stream; 00069 int len, remain; 00070 00071 len = job->write_len; 00072 assert(len > 0); 00073 00074 assert(len > 0); 00075 if ((size_t)len > stream->avail_out) 00076 len = stream->avail_out; 00077 00078 if (!stream->avail_out) { 00079 rs_trace("no output space available"); 00080 return; 00081 } 00082 00083 memcpy(stream->next_out, job->write_buf, len); 00084 stream->next_out += len; 00085 stream->avail_out -= len; 00086 00087 remain = job->write_len - len; 00088 rs_trace("transmitted %d write bytes from tube, %d remain to be sent", len, 00089 remain); 00090 00091 if (remain > 0) { 00092 /* Still something left in the tube... */ 00093 memmove(job->write_buf, job->write_buf + len, remain); 00094 } else { 00095 assert(remain == 0); 00096 } 00097 00098 job->write_len = remain; 00099 } 00100 00101 /** Execute a copy command, taking data from the scoop. 00102 * 00103 * \sa rs_tube_catchup_copy() */ 00104 static void rs_tube_copy_from_scoop(rs_job_t *job) 00105 { 00106 size_t this_len; 00107 rs_buffers_t *stream = job->stream; 00108 00109 this_len = 00110 job->copy_len < job->scoop_avail ? job->copy_len : job->scoop_avail; 00111 if (this_len > stream->avail_out) { 00112 this_len = stream->avail_out; 00113 } 00114 memcpy(stream->next_out, job->scoop_next, this_len); 00115 00116 stream->next_out += this_len; 00117 stream->avail_out -= this_len; 00118 00119 job->scoop_avail -= this_len; 00120 job->scoop_next += this_len; 00121 00122 job->copy_len -= this_len; 00123 00124 rs_trace("caught up on " FMT_SIZE " copied bytes from scoop, " FMT_SIZE 00125 " remain there, " FMT_LONG " remain to be copied", this_len, 00126 job->scoop_avail, job->copy_len); 00127 } 00128 00129 /** Catch up on an outstanding copy command. 00130 * 00131 * Takes data from the scoop, and the input (in that order), and writes as much 00132 * as will fit to the output, up to the limit of the outstanding copy. */ 00133 static void rs_tube_catchup_copy(rs_job_t *job) 00134 { 00135 assert(job->write_len == 0); 00136 assert(job->copy_len > 0); 00137 00138 /* If there's data in the scoop, send that first. */ 00139 if (job->scoop_avail && job->copy_len) { 00140 rs_tube_copy_from_scoop(job); 00141 } 00142 /* If there's more to copy and we emptied the scoop, send input. */ 00143 if (job->copy_len && !job->scoop_avail) { 00144 size_t this_copy = rs_buffers_copy(job->stream, job->copy_len); 00145 job->copy_len -= this_copy; 00146 rs_trace("copied " FMT_SIZE " bytes from input buffer, " FMT_LONG 00147 " remain to be copied", this_copy, job->copy_len); 00148 } 00149 } 00150 00151 /** Put whatever will fit from the tube into the output of the stream. 00152 * 00153 * \return RS_DONE if the tube is now empty and ready to accept another 00154 * command, RS_BLOCKED if there is still stuff waiting to go out. */ 00155 int rs_tube_catchup(rs_job_t *job) 00156 { 00157 if (job->write_len) { 00158 rs_tube_catchup_write(job); 00159 if (job->write_len) 00160 return RS_BLOCKED; 00161 } 00162 00163 if (job->copy_len) { 00164 rs_tube_catchup_copy(job); 00165 if (job->copy_len) { 00166 if (job->stream->eof_in && !job->stream->avail_in 00167 && !job->scoop_avail) { 00168 rs_error 00169 ("reached end of file while copying literal data through buffers"); 00170 return RS_INPUT_ENDED; 00171 } 00172 return RS_BLOCKED; 00173 } 00174 } 00175 return RS_DONE; 00176 } 00177 00178 /* Check whether there is data in the tube waiting to go out. 00179 00180 \return true if the previous command has finished doing all its output. */ 00181 int rs_tube_is_idle(rs_job_t const *job) 00182 { 00183 return job->write_len == 0 && job->copy_len == 0; 00184 } 00185 00186 /** Queue up a request to copy through \p len bytes from the input to the 00187 * output of the stream. 00188 * 00189 * The data is copied from the scoop (if there is anything there) or from the 00190 * input, on the next call to rs_tube_write(). 00191 * 00192 * We can only accept this request if there is no copy command already pending. 00193 * 00194 * \todo Try to do the copy immediately, and return a result. Then, people can 00195 * try to continue if possible. Is this really required? Callers can just go 00196 * out and back in again after flushing the tube. */ 00197 void rs_tube_copy(rs_job_t *job, int len) 00198 { 00199 assert(job->copy_len == 0); 00200 00201 job->copy_len = len; 00202 } 00203 00204 /** Push some data into the tube for storage. 00205 * 00206 * The tube's never supposed to get very big, so this will just pop loudly if 00207 * you do that. 00208 * 00209 * We can't accept write data if there's already a copy command in the tube, 00210 * because the write data comes out first. */ 00211 void rs_tube_write(rs_job_t *job, const void *buf, size_t len) 00212 { 00213 assert(job->copy_len == 0); 00214 00215 if (len > sizeof(job->write_buf) - job->write_len) { 00216 rs_fatal("tube popped when trying to write " FMT_SIZE " bytes!", len); 00217 } 00218 00219 memcpy(job->write_buf + job->write_len, buf, len); 00220 job->write_len += len; 00221 }