0540845bb03275f594a7e31c661ff5d33383144a
[debian/amanda] / server-src / taper-mem-port-source.c
1 /*
2  * Amanda, The Advanced Maryland Automatic Network Disk Archiver
3  * Copyright (c) 2006 Zmanda Inc.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18  */
19
20 #define selfp (self->_priv)
21
22 #include "taper-mem-port-source.h"
23
24 #include "physmem.h"
25
26 struct _TaperMemPortSourcePrivate {
27     /* Actual size of this buffer is given by max_part_size in TaperSource. */
28     char * retry_buffer;
29     guint64 buffer_offset; /* Bytes read from buffer. */
30     guint64 buffer_len;    /* Bytes written to buffer. */
31     gboolean retry_mode;
32 };
33 /* here are local prototypes */
34 static void taper_mem_port_source_init (TaperMemPortSource * o);
35 static void taper_mem_port_source_class_init (TaperMemPortSourceClass * c);
36 static ssize_t taper_mem_port_source_read (TaperSource * pself, void * buf,
37                                            size_t count);
38 static gboolean taper_mem_port_source_seek_to_part_start (TaperSource * pself);
39 static void taper_mem_port_source_start_new_part (TaperSource * pself);
40 static int taper_mem_port_source_predict_parts(TaperSource * pself);
41
42 /* pointer to the class of our parent */
43 static TaperSourceClass * source_parent_class = NULL;
44 static TaperPortSourceClass *parent_class = NULL;
45
46 GType
47 taper_mem_port_source_get_type (void)
48 {
49     static GType type = 0;
50     
51     if G_UNLIKELY(type == 0) {
52         static const GTypeInfo info = {
53             sizeof (TaperMemPortSourceClass),
54             (GBaseInitFunc) NULL,
55             (GBaseFinalizeFunc) NULL,
56             (GClassInitFunc) taper_mem_port_source_class_init,
57             (GClassFinalizeFunc) NULL,
58             NULL /* class_data */,
59             sizeof (TaperMemPortSource),
60             0 /* n_preallocs */,
61             (GInstanceInitFunc) taper_mem_port_source_init,
62             NULL
63         };
64         
65         type = g_type_register_static (TAPER_TYPE_PORT_SOURCE,
66                                        "TaperMemPortSource", &info,
67                                        (GTypeFlags)0);
68     }
69     
70     return type;
71 }
72
73 static void
74 taper_mem_port_source_finalize(GObject *obj_self) {
75     TaperMemPortSource *self = TAPER_MEM_PORT_SOURCE (obj_self);
76     if(G_OBJECT_CLASS(parent_class)->finalize)
77         (* G_OBJECT_CLASS(parent_class)->finalize)(obj_self);
78     amfree (self->_priv->retry_buffer);
79     amfree (self->_priv);
80 }
81
82 static void 
83 taper_mem_port_source_init (TaperMemPortSource * o) {
84     o->_priv = malloc(sizeof(TaperMemPortSourcePrivate));
85     o->_priv->retry_buffer = NULL;
86     o->_priv->retry_mode = FALSE;
87     o->_priv->buffer_offset = o->_priv->buffer_len = 0;
88 }
89
90 static void 
91 taper_mem_port_source_class_init (TaperMemPortSourceClass * c) {
92     GObjectClass *g_object_class = (GObjectClass*) c;
93     TaperSourceClass *taper_source_class = (TaperSourceClass *)c;
94     
95     parent_class = g_type_class_ref (TAPER_TYPE_PORT_SOURCE);
96     source_parent_class = (TaperSourceClass*)parent_class;
97     
98     taper_source_class->read = taper_mem_port_source_read;
99     taper_source_class->seek_to_part_start =
100         taper_mem_port_source_seek_to_part_start;
101     taper_source_class->start_new_part = taper_mem_port_source_start_new_part;
102     taper_source_class->predict_parts = taper_mem_port_source_predict_parts;
103
104     g_object_class->finalize = taper_mem_port_source_finalize;
105 }
106
107 static int taper_mem_port_source_predict_parts(TaperSource * pself) {
108     TaperMemPortSource * self = TAPER_MEM_PORT_SOURCE(pself);
109     g_return_val_if_fail(self != NULL, -1);
110
111     return -1;
112 }
113
114 /* Allocate buffer space, if it hasn't been done yet. */
115 static void setup_retry_buffer(TaperMemPortSource * self) {
116     guint64 alloc_size;
117     guint64 max_usage;
118     if (selfp->retry_buffer != NULL)
119         return;
120
121     alloc_size = TAPER_SOURCE(self)->max_part_size;
122     if (alloc_size > SIZE_MAX) {
123         g_fprintf(stderr, "Fallback split size of %lld is greater that system maximum of %lld.\n",
124                 (long long)alloc_size, (long long)SIZE_MAX);
125         alloc_size = SIZE_MAX;
126     }
127     
128     max_usage = physmem_available() * .95;
129     if (alloc_size > max_usage) {
130         g_fprintf(stderr, "Fallback split size of %lld is greater than 95%% of available memory (%lld bytes).\n", (long long)alloc_size, (long long)max_usage);
131         alloc_size = max_usage;
132     }
133     
134     if (alloc_size < DISK_BLOCK_BYTES * 10) {
135         g_fprintf(stderr, "Fallback split size of %ju is smaller than 10 blocks (%u bytes).\n",
136                   (uintmax_t)alloc_size, DISK_BLOCK_BYTES * 10);
137         alloc_size = DISK_BLOCK_BYTES * 10;
138     }
139     
140     TAPER_SOURCE(self)->max_part_size = alloc_size;
141     selfp->retry_buffer = malloc(alloc_size);
142 }
143
144 static ssize_t 
145 taper_mem_port_source_read (TaperSource * pself, void * buf, size_t count) {
146     TaperMemPortSource * self = (TaperMemPortSource*)pself;
147     g_return_val_if_fail (self != NULL, -1);
148     g_return_val_if_fail (TAPER_IS_MEM_PORT_SOURCE (self), -1);
149     g_return_val_if_fail (buf != NULL, -1);
150     g_return_val_if_fail (count > 0, -1);
151     
152     if (selfp->retry_mode) {
153         g_assert(selfp->retry_buffer != NULL && selfp->buffer_len > 0);
154         count = MIN(count, selfp->buffer_len - selfp->buffer_offset);
155
156         if (count == 0) {
157             /* It was not before. */
158             pself->end_of_part = TRUE;
159             return 0;
160         }
161
162         memcpy(buf, selfp->retry_buffer + selfp->buffer_offset, count);
163         selfp->buffer_offset += count;
164         return count;
165     } else {
166         int read_result;
167         if (selfp->retry_buffer == NULL) {
168             setup_retry_buffer(self);
169         }
170
171         count = MIN(count, pself->max_part_size - selfp->buffer_len);
172         if (count == 0) /* it was nonzero before */ {
173             pself->end_of_part = TRUE;
174             return 0;
175         }
176         
177         read_result = source_parent_class->read(pself, buf, count);
178         /* TaperPortSource handles EOF and other goodness. */
179         if (read_result <= 0) {
180             return read_result;
181         }
182
183         /* All's well in the world. */
184         memcpy(selfp->retry_buffer + selfp->buffer_len,
185                buf, read_result);
186         selfp->buffer_len += read_result;
187
188         return read_result;
189     }
190
191     g_assert_not_reached();
192 }
193
194 static gboolean 
195 taper_mem_port_source_seek_to_part_start (TaperSource * pself) {
196     TaperMemPortSource * self = (TaperMemPortSource*)pself;
197     g_return_val_if_fail (self != NULL, FALSE);
198     g_return_val_if_fail (TAPER_IS_MEM_PORT_SOURCE (self), FALSE);
199     g_return_val_if_fail (selfp->buffer_len > 0, FALSE);
200
201     selfp->retry_mode = TRUE;
202     selfp->buffer_offset = 0;
203
204     if (source_parent_class->seek_to_part_start)
205         return source_parent_class->seek_to_part_start(pself);
206     else
207         return TRUE;
208 }
209
210 static void 
211 taper_mem_port_source_start_new_part (TaperSource * pself) {
212     TaperMemPortSource * self = (TaperMemPortSource*)pself;
213     g_return_if_fail (self != NULL);
214     g_return_if_fail (TAPER_IS_MEM_PORT_SOURCE (self));
215
216     selfp->buffer_offset = selfp->buffer_len = 0;
217     selfp->retry_mode = FALSE;
218
219     if (source_parent_class->start_new_part)
220         source_parent_class->start_new_part(pself);
221 }