source: lib/ior-peek.c @ 22a9ccc

4.0.1-hotfixescachetimestampsdevelopdpdk-ndagetsilivegetfragoffhelplibtrace4ndag_formatpfringrc-4.0.1rc-4.0.2rc-4.0.3rc-4.0.4ringdecrementfixringperformanceringtimestampfixes
Last change on this file since 22a9ccc was 22a9ccc, checked in by Shane Alcock <salcock@…>, 12 years ago
  • Updated licensing and documentation for all the IO writer modules
  • Got rid of annoying "Write thread leaving" message!
  • Added Id keyword support to all IO modules
  • Property mode set to 100644
File size: 5.2 KB
Line 
1/*
2 * This file is part of libtrace
3 *
4 * Copyright (c) 2007,2008,2009,2010 The University of Waikato, Hamilton,
5 * New Zealand.
6 *
7 * Authors: Daniel Lawson
8 *          Perry Lorier
9 *          Shane Alcock
10 *         
11 * All rights reserved.
12 *
13 * This code has been developed by the University of Waikato WAND
14 * research group. For further information please see http://www.wand.net.nz/
15 *
16 * libtrace is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation; either version 2 of the License, or
19 * (at your option) any later version.
20 *
21 * libtrace is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24 * GNU General Public License for more details.
25 *
26 * You should have received a copy of the GNU General Public License
27 * along with libtrace; if not, write to the Free Software
28 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
29 *
30 * $Id$
31 *
32 */
33
34#include "wandio.h"
35#include <sys/types.h>
36#include <sys/stat.h>
37#include <fcntl.h>
38#include <stdlib.h>
39#include <unistd.h>
40#include <string.h>
41
42/* Libtrace IO module implementing a peeking reader.
43 *
44 * Assuming my understanding of Perry's code is correct, this module provides
45 * generic support for "peeking" that can be used in concert with any other
46 * implemented IO reader.
47 *
48 * The other IO reader is a "child" to the peeking reader and is used to read
49 * the data into a buffer managed by the peeking reader. Any actual "peeks"
50 * are serviced from the managed buffer, which means that we do not have to
51 * manipulate the read offsets directly in zlib or bzip, for instance.
52 */
53
54struct peek_t {
55        io_t *child;
56        char *buffer;
57        int length;
58        int offset;
59};
60
61extern io_source_t peek_source;
62
63#define DATA(io) ((struct peek_t *)((io)->data))
64#define MIN(a,b) ((a) < (b) ? (a) : (b))
65
66io_t *peek_open(io_t *child)
67{
68        io_t *io;
69        if (!child)
70                return NULL;
71        io =  malloc(sizeof(io_t));
72        io->data = malloc(sizeof(struct peek_t));
73        io->source = &peek_source;
74
75        /* Wrap the peeking reader around the "child" */
76        DATA(io)->child = child;
77        DATA(io)->buffer = NULL;
78        DATA(io)->length = 0;
79        DATA(io)->offset = 0;   
80
81        return io;
82}
83
84static off_t peek_read(io_t *io, void *buffer, off_t len)
85{
86        off_t ret = 0;
87
88        /* Is some of this data in the buffer? */
89        if (DATA(io)->buffer) {
90                ret = MIN(len,DATA(io)->length - DATA(io)->offset);
91
92                /* Copy everything we've got into their buffer, and shift our
93                 * offset so that we don't peek at the data we've read again */
94                memcpy(buffer, 
95                        DATA(io)->buffer + DATA(io)->offset,
96                        ret);
97                buffer += ret;
98                DATA(io)->offset += ret;
99                len -= ret;
100        }
101        /* Use the child reader to get the rest of the required data */
102        if (len>0) {
103                off_t bytes_read = 
104                        DATA(io)->child->source->read(
105                                DATA(io)->child, buffer, len);
106                /* Error? */
107                if (bytes_read < 1) {
108                        /* Return if we have managed to get some data ok */
109                        if (ret > 0)
110                                return ret;
111                        /* Return the error upstream */
112                        return bytes_read;
113                }
114                ret += bytes_read;
115        }
116
117        /* Have we read past the end of the buffer? */
118        if (DATA(io)->buffer && DATA(io)->offset >= DATA(io)->length) {
119                /* If so, free the memory it used */
120                free(DATA(io)->buffer);
121                DATA(io)->buffer = NULL;
122                DATA(io)->offset = 0;
123                DATA(io)->length = 0;
124        }
125
126        return ret;
127}
128
129/* Round reads for peeks into the buffer up to this size */
130#define PEEK_SIZE (1024*1024)
131
132static off_t peek_peek(io_t *io, void *buffer, off_t len)
133{
134        off_t ret = 0;
135
136        /* Is there enough data in the buffer to serve this request? */
137        if (DATA(io)->length - DATA(io)->offset < len) {
138                /* No, we need to extend the buffer. */
139                off_t read_amount = len - (DATA(io)->length - DATA(io)->offset);
140                /* Round the read_amount up to the nearest MB */
141                read_amount += PEEK_SIZE - ((DATA(io)->length + read_amount) % PEEK_SIZE);
142                DATA(io)->buffer = realloc(DATA(io)->buffer, DATA(io)->length + read_amount);
143                /* Use the child reader to read more data into our managed
144                 * buffer */
145                read_amount = wandio_read(DATA(io)->child, 
146                        DATA(io)->buffer + DATA(io)->length,
147                        read_amount);
148
149                /* Pass errors up */
150                if (read_amount <1) {
151                        return read_amount;
152                }
153
154                DATA(io)->length += read_amount;
155        }
156
157        /* Right, now return data from the buffer (that now should be large
158         * enough, but might not be if we hit EOF) */
159        ret = MIN(len, DATA(io)->length - DATA(io)->offset);
160        memcpy(buffer, DATA(io)->buffer + DATA(io)->offset, ret);
161        return ret;
162}
163
164static off_t peek_tell(io_t *io)
165{
166        /* We don't actually maintain a read offset as such, so we want to
167         * return the child's read offset */
168        return wandio_tell(DATA(io)->child);
169}
170
171static off_t peek_seek(io_t *io, off_t offset, int whence)
172{
173        /* Again, we don't have a genuine read offset so we need to pass this
174         * one on to the child */
175        return wandio_seek(DATA(io)->child,offset,whence);
176}
177
178static void peek_close(io_t *io)
179{
180        /* Make sure we close the child that is doing the actual reading! */
181        wandio_destroy(DATA(io)->child);
182        if (DATA(io)->buffer)
183                free(DATA(io)->buffer);
184        free(io->data);
185        free(io);
186}
187
188io_source_t peek_source = {
189        "peek",
190        peek_read,
191        peek_peek,
192        peek_tell,
193        peek_seek,
194        peek_close
195};
196
Note: See TracBrowser for help on using the repository browser.