librsync  2.0.1
tube.c
1 /*= -*- c-basic-offset: 4; indent-tabs-mode: nil; -*-
2  *
3  * librsync -- dynamic caching and delta update in HTTP
4  *
5  * Copyright (C) 2000, 2001 by Martin Pool <mbp@sourcefrog.net>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU Lesser General Public License as published by
9  * the Free Software Foundation; either version 2.1 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20  */
21 
22  /*
23  | Where a calculator on the ENIAC is
24  | equpped with 18,000 vaccuum tubes and
25  | weighs 30 tons, computers in the
26  | future may have only 1,000 vaccuum
27  | tubes and perhaps weigh 1 1/2
28  | tons.
29  | -- Popular Mechanics, March 1949
30  */
31 
32 
33 /* tube: a somewhat elastic but fairly small buffer for data passing
34  * through a stream.
35  *
36  * In most cases the iter can adjust to send just as much data will
37  * fit. In some cases that would be too complicated, because it has
38  * to transmit an integer or something similar. So in that case we
39  * stick whatever won't fit into a small buffer.
40  *
41  * A tube can contain some literal data to go out (typically command
42  * bytes), and also an instruction to copy data from the stream's
43  * input or from some other location. Both literal data and a copy
44  * command can be queued at the same time, but only in that order and
45  * at most one of each. */
46 
47 
48 /*
49  * TODO: As an optimization, write it directly to the stream if
50  * possible. But for simplicity don't do that yet.
51  *
52  * TODO: I think our current copy code will lock up if the application
53  * only ever calls us with either input or output buffers, and not
54  * both. So I guess in that case we might need to copy into some
55  * temporary buffer space, and then back out again later.
56  */
57 
58 
59 #include "config.h"
60 
61 #include <assert.h>
62 #include <stdlib.h>
63 #include <string.h>
64 #include <stdio.h>
65 
66 #include "librsync.h"
67 #include "trace.h"
68 #include "util.h"
69 #include "job.h"
70 #include "stream.h"
71 
72 
73 static void rs_tube_catchup_write(rs_job_t *job)
74 {
75  rs_buffers_t *stream = job->stream;
76  int len, remain;
77 
78  len = job->write_len;
79  assert(len > 0);
80 
81  assert(len > 0);
82  if ((size_t) len > stream->avail_out)
83  len = stream->avail_out;
84 
85  if (!stream->avail_out) {
86  rs_trace("no output space available");
87  return;
88  }
89 
90  memcpy(stream->next_out, job->write_buf, len);
91  stream->next_out += len;
92  stream->avail_out -= len;
93 
94  remain = job->write_len - len;
95  rs_trace("transmitted %d write bytes from tube, "
96  "%d remain to be sent",
97  len, remain);
98 
99  if (remain > 0) {
100  /* Still something left in the tube... */
101  memmove(job->write_buf, job->write_buf + len, remain);
102  } else {
103  assert(remain == 0);
104  }
105 
106  job->write_len = remain;
107 }
108 
109 
110 /**
111  * Execute a copy command, taking data from the scoop.
112  *
113  * \sa rs_tube_catchup_copy()
114  */
115 static void
116 rs_tube_copy_from_scoop(rs_job_t *job)
117 {
118  size_t this_len;
119  rs_buffers_t *stream = job->stream;
120 
121  this_len = job->copy_len;
122  if (this_len > job->scoop_avail) {
123  this_len = job->scoop_avail;
124  }
125  if (this_len > stream->avail_out) {
126  this_len = stream->avail_out;
127  }
128 
129  memcpy(stream->next_out, job->scoop_next, this_len);
130 
131  stream->next_out += this_len;
132  stream->avail_out -= this_len;
133 
134  job->scoop_avail -= this_len;
135  job->scoop_next += this_len;
136 
137  job->copy_len -= this_len;
138 
139  rs_trace("caught up on %ld copied bytes from scoop, %ld remain there, "
140  "%ld remain to be copied",
141  (long) this_len, (long) job->scoop_avail, (long) job->copy_len);
142 }
143 
144 
145 
146 /**
147  * Catch up on an outstanding copy command.
148  *
149  * Takes data from the scoop, and the input (in that order), and
150  * writes as much as will fit to the output, up to the limit of the
151  * outstanding copy.
152  */
153 static void rs_tube_catchup_copy(rs_job_t *job)
154 {
155  rs_buffers_t *stream = job->stream;
156 
157  assert(job->write_len == 0);
158  assert(job->copy_len > 0);
159 
160  if (job->scoop_avail && job->copy_len) {
161  /* there's still some data in the scoop, so we should use that. */
162  rs_tube_copy_from_scoop(job);
163  }
164 
165  if (job->copy_len) {
166  size_t this_copy;
167 
168  this_copy = rs_buffers_copy(stream, job->copy_len);
169 
170  job->copy_len -= this_copy;
171 
172  rs_trace("copied " PRINTF_FORMAT_U64 " bytes from input buffer, " PRINTF_FORMAT_U64 " remain to be copied",
173  PRINTF_CAST_U64(this_copy), PRINTF_CAST_U64(job->copy_len));
174  }
175 }
176 
177 
178 /*
179  * Put whatever will fit from the tube into the output of the stream.
180  * Return RS_DONE if the tube is now empty and ready to accept another
181  * command, RS_BLOCKED if there is still stuff waiting to go out.
182  */
183 int rs_tube_catchup(rs_job_t *job)
184 {
185  if (job->write_len)
186  rs_tube_catchup_write(job);
187 
188  if (job->write_len) {
189  /* there is still write data queued, so we can't send
190  * anything else. */
191  return RS_BLOCKED;
192  }
193 
194  if (job->copy_len)
195  rs_tube_catchup_copy(job);
196 
197  if (job->copy_len) {
198  if (job->stream->eof_in && !job->stream->avail_in && !job->scoop_avail) {
199  rs_log(RS_LOG_ERR,
200  "reached end of file while copying literal data through buffers");
201  return RS_INPUT_ENDED;
202  }
203 
204  return RS_BLOCKED;
205  }
206 
207  return RS_DONE;
208 }
209 
210 
211 /* Check whether there is data in the tube waiting to go out. So if true
212  * this basically means that the previous command has finished doing all its
213  * output. */
214 int rs_tube_is_idle(rs_job_t const *job)
215 {
216  return job->write_len == 0 && job->copy_len == 0;
217 }
218 
219 
220 /**
221  * Queue up a request to copy through \p len bytes from the input to
222  * the output of the stream.
223  *
224  * The data is copied from the scoop (if there is anything there) or
225  * from the input, on the next call to rs_tube_write().
226  *
227  * We can only accept this request if there is no copy command already
228  * pending.
229  */
230 /* TODO: Try to do the copy immediately, and return a result. Then,
231  * people can try to continue if possible. Is this really required?
232  * Callers can just go out and back in again after flushing the
233  * tube. */
234 void rs_tube_copy(rs_job_t *job, int len)
235 {
236  assert(job->copy_len == 0);
237 
238  job->copy_len = len;
239 }
240 
241 
242 
243 /*
244  * Push some data into the tube for storage. The tube's never
245  * supposed to get very big, so this will just pop loudly if you do
246  * that.
247  *
248  * We can't accept write data if there's already a copy command in the
249  * tube, because the write data comes out first.
250  */
251 void
252 rs_tube_write(rs_job_t *job, const void *buf, size_t len)
253 {
254  assert(job->copy_len == 0);
255 
256  if (len > sizeof(job->write_buf) - job->write_len) {
257  rs_fatal("tube popped when trying to write %ld bytes!",
258  (long) len);
259  }
260 
261  memcpy(job->write_buf + job->write_len, buf, len);
262  job->write_len += len;
263 }
Description of input and output buffers.
Definition: librsync.h:361
rs_long_t copy_len
If copy_len is >0, then that much data should be copied through from the input.
Definition: job.h:95
rs_byte_t write_buf[36]
If USED is >0, then buf contains that much write data to be sent out.
Definition: job.h:90
size_t avail_out
Remaining free space at next_out.
Definition: librsync.h:397
char * next_out
Next output byte should be put there References a pointer which on entry points to the start of the o...
Definition: librsync.h:389
size_t avail_in
Number of bytes available at next_in References the length of available input.
Definition: librsync.h:376
Error conditions.
Definition: librsync.h:123
Public header for librsync.
Unexpected end of input file, perhaps due to a truncated file or dropped network connection.
Definition: librsync.h:208
Blocked waiting for more data.
Definition: librsync.h:195
int eof_in
True if there is no more data after this.
Definition: librsync.h:381
Completed successfully.
Definition: librsync.h:194
The contents of this structure are private.
Definition: job.h:29