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.5 2005/09/06 06:42:44 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 jfile *jf, 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_transid ^ head->streamid) & JREC_STREAMID_MASK) == 0)
89 jh = malloc(sizeof(*jh));
90 bzero(jh, sizeof(*jh));
94 jh->jh_transid = head->streamid;
99 * Emplace the stream segment
101 jh->jh_transid |= head->streamid & JREC_STREAMCTL_MASK;
102 if (jf->jf_direction == JD_FORWARDS) {
103 jh->jh_last->js_next = js;
106 js->js_next = jh->jh_first;
111 * If the transaction is complete, remove the hash entry and return the
112 * js representing the beginning of the transaction.
114 if ((jh->jh_transid & (JREC_STREAMCTL_BEGIN|JREC_STREAMCTL_END)) ==
115 (JREC_STREAMCTL_BEGIN|JREC_STREAMCTL_END)
129 * Renormalize the jscan list to remove all the meta record headers
130 * and trailers except for the very first one.
134 jnormalize(struct jstream *js)
136 struct jstream *jscan;
139 js->js_normalized_off = 0;
140 js->js_normalized_base = (void *)js->js_head;
141 js->js_normalized_size = js->js_head->recsize - sizeof(struct journal_rawrecend);
142 js->js_normalized_total = js->js_normalized_size;
143 off = js->js_normalized_size;
144 for (jscan = js->js_next; jscan; jscan = jscan->js_next) {
145 jscan->js_normalized_off = off;
146 jscan->js_normalized_base = (char *)jscan->js_head +
147 sizeof(struct journal_rawrecbeg);
148 jscan->js_normalized_size = jscan->js_head->recsize -
149 sizeof(struct journal_rawrecbeg) -
150 sizeof(struct journal_rawrecend);
151 off += jscan->js_normalized_size;
152 js->js_normalized_total += jscan->js_normalized_size;
157 jscan_dispose(struct jstream *js)
159 struct jstream *jnext;
161 if (js->js_alloc_buf) {
162 free(js->js_alloc_buf);
163 js->js_alloc_buf = NULL;
164 js->js_alloc_size = 0;
169 jfree(js->js_jfile, js->js_jdata);
177 * Read the specified block of data out of a linked set of jstream
178 * structures. Returns 0 on success or an error code on error.
181 jsread(struct jstream *js, off_t off, void *buf, int bytes)
187 n = jsreadany(js, off, &ptr);
193 buf = (char *)buf + n;
201 * Read the specified block of data out of a linked set of jstream
202 * structures. Attempt to return a pointer into the data set but
203 * allocate and copy if that is not possible. Returns 0 on success
204 * or an error code on error.
207 jsreadp(struct jstream *js, off_t off, const void **bufp,
213 n = jsreadany(js, off, bufp);
215 if (js->js_alloc_size < bytes) {
216 if (js->js_alloc_buf)
217 free(js->js_alloc_buf);
218 js->js_alloc_buf = malloc(bytes);
219 js->js_alloc_size = bytes;
220 assert(js->js_alloc_buf != NULL);
222 error = jsread(js, off, js->js_alloc_buf, bytes);
226 *bufp = js->js_alloc_buf;
233 jsreadcallback(struct jstream *js, ssize_t (*func)(int, const void *, size_t),
234 int fd, off_t off, int bytes)
242 while (bytes && (n = jsreadany(js, off, &bufp)) > 0) {
245 r = func(fd, bufp, n);
258 * Return the largest contiguous buffer starting at the specified offset,
262 jsreadany(struct jstream *js, off_t off, const void **bufp)
264 struct jstream *scan;
267 if ((scan = js->js_cache) == NULL || scan->js_normalized_off > off)
269 while (scan && scan->js_normalized_off <= off) {
271 if (scan->js_normalized_off + scan->js_normalized_size > off) {
272 n = (int)(off - scan->js_normalized_off);
273 *bufp = scan->js_normalized_base + n;
274 return(scan->js_normalized_size - n);
276 scan = scan->js_next;