2 * Copyright (c) 2004,2005 The DragonFly Project. All rights reserved.
4 * This code is derived from software contributed to The DragonFly Project
5 * by Matthew Dillon <dillon@backplane.com>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
17 * 3. Neither the name of The DragonFly Project nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific, prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * $DragonFly: src/sbin/jscan/jstream.c,v 1.6 2005/09/06 18:43:52 dillon Exp $
39 static struct jhash *JHashAry[JHASH_SIZE];
41 static void jnormalize(struct jstream *js);
44 * Integrate a raw record. Deal with the transaction begin and end flags
45 * to create a forward-referenced collection of jstream records. If we are
46 * able to complete a transaction, the first js associated with that
47 * transaction is returned.
49 * XXX we need to store the data for very large multi-record transactions
50 * separately since it might not fit into memory.
53 jaddrecord(struct jsession *ss, struct jdata *jd)
55 struct journal_rawrecbeg *head;
60 js = malloc(sizeof(struct jstream));
61 bzero(js, sizeof(struct jstream));
62 js->js_jdata = jref(jd);
63 js->js_head = (void *)jd->jd_data;
68 * Check for a completely self-contained transaction, just return the
71 if ((head->streamid & (JREC_STREAMCTL_BEGIN|JREC_STREAMCTL_END)) ==
72 (JREC_STREAMCTL_BEGIN|JREC_STREAMCTL_END)
79 * Check for an open transaction in the hash table, create a new one
82 jhp = &JHashAry[head->streamid & JHASH_MASK];
83 while ((jh = *jhp) != NULL) {
84 if (jh->jh_session == ss &&
85 ((jh->jh_transid ^ head->streamid) & JREC_STREAMID_MASK) == 0
92 jh = malloc(sizeof(*jh));
93 bzero(jh, sizeof(*jh));
97 jh->jh_transid = head->streamid;
103 * Emplace the stream segment
105 jh->jh_transid |= head->streamid & JREC_STREAMCTL_MASK;
106 if (js->js_session->ss_jfin->jf_direction == JD_FORWARDS) {
107 jh->jh_last->js_next = js;
110 js->js_next = jh->jh_first;
115 * If the transaction is complete, remove the hash entry and return the
116 * js representing the beginning of the transaction.
118 if ((jh->jh_transid & (JREC_STREAMCTL_BEGIN|JREC_STREAMCTL_END)) ==
119 (JREC_STREAMCTL_BEGIN|JREC_STREAMCTL_END)
133 * Renormalize the jscan list to remove all the meta record headers
134 * and trailers except for the very first one.
138 jnormalize(struct jstream *js)
140 struct jstream *jscan;
143 js->js_normalized_off = 0;
144 js->js_normalized_base = (void *)js->js_head;
145 js->js_normalized_size = js->js_head->recsize - sizeof(struct journal_rawrecend);
146 js->js_normalized_total = js->js_normalized_size;
147 off = js->js_normalized_size;
148 for (jscan = js->js_next; jscan; jscan = jscan->js_next) {
149 jscan->js_normalized_off = off;
150 jscan->js_normalized_base = (char *)jscan->js_head +
151 sizeof(struct journal_rawrecbeg);
152 jscan->js_normalized_size = jscan->js_head->recsize -
153 sizeof(struct journal_rawrecbeg) -
154 sizeof(struct journal_rawrecend);
155 off += jscan->js_normalized_size;
156 js->js_normalized_total += jscan->js_normalized_size;
161 jscan_dispose(struct jstream *js)
163 struct jstream *jnext;
165 if (js->js_alloc_buf) {
166 free(js->js_alloc_buf);
167 js->js_alloc_buf = NULL;
168 js->js_alloc_size = 0;
173 jfree(js->js_session->ss_jfin, js->js_jdata);
181 * Read the specified block of data out of a linked set of jstream
182 * structures. Returns 0 on success or an error code on error.
185 jsread(struct jstream *js, off_t off, void *buf, int bytes)
191 n = jsreadany(js, off, &ptr);
197 buf = (char *)buf + n;
205 * Read the specified block of data out of a linked set of jstream
206 * structures. Attempt to return a pointer into the data set but
207 * allocate and copy if that is not possible. Returns 0 on success
208 * or an error code on error.
211 jsreadp(struct jstream *js, off_t off, const void **bufp,
217 n = jsreadany(js, off, bufp);
219 if (js->js_alloc_size < bytes) {
220 if (js->js_alloc_buf)
221 free(js->js_alloc_buf);
222 js->js_alloc_buf = malloc(bytes);
223 js->js_alloc_size = bytes;
224 assert(js->js_alloc_buf != NULL);
226 error = jsread(js, off, js->js_alloc_buf, bytes);
230 *bufp = js->js_alloc_buf;
237 jsreadcallback(struct jstream *js, ssize_t (*func)(int, const void *, size_t),
238 int fd, off_t off, int bytes)
246 while (bytes && (n = jsreadany(js, off, &bufp)) > 0) {
249 r = func(fd, bufp, n);
262 * Return the largest contiguous buffer starting at the specified offset,
266 jsreadany(struct jstream *js, off_t off, const void **bufp)
268 struct jstream *scan;
271 if ((scan = js->js_cache) == NULL || scan->js_normalized_off > off)
273 while (scan && scan->js_normalized_off <= off) {
275 if (scan->js_normalized_off + scan->js_normalized_size > off) {
276 n = (int)(off - scan->js_normalized_off);
277 *bufp = scan->js_normalized_base + n;
278 return(scan->js_normalized_size - n);
280 scan = scan->js_next;