add a sync wrapper for the getpnn control
[metze/ctdb/wip.git] / libctdb / io_elem.c
1 /*
2    Simple queuing of input and output records for libctdb
3
4    Copyright (C) Rusty Russell 2010
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, see <http://www.gnu.org/licenses/>.
18 */
19 #include <sys/types.h>
20 #include <stdint.h>
21 #include <stdbool.h>
22 #include <unistd.h>
23 #include <errno.h>
24 #include <stdlib.h>
25 #include "io_elem.h"
26 #include <tdb.h>
27 #include <ctdb_protocol.h> // For CTDB_DS_ALIGNMENT and ctdb_req_header
28
29 struct io_elem {
30         size_t len, off;
31         char *data;
32 };
33
34 struct io_elem *new_io_elem(size_t len)
35 {
36         struct io_elem *elem;
37         len = (len + (CTDB_DS_ALIGNMENT-1)) & ~(CTDB_DS_ALIGNMENT-1);
38
39         elem = malloc(sizeof(*elem));
40         if (!elem)
41                 return NULL;
42         elem->data = malloc(len);
43         if (!elem->data) {
44                 free(elem);
45                 return NULL;
46         }
47
48         elem->len = len;
49         elem->off = 0;
50         return elem;
51 }
52
53 void free_io_elem(struct io_elem *io)
54 {
55         free(io->data);
56         free(io);
57 }
58
59 bool io_elem_finished(const struct io_elem *io)
60 {
61         return io->off == io->len;
62 }
63
64 void io_elem_init_req_header(struct io_elem *io,
65                              uint32_t operation,
66                              uint32_t destnode,
67                              uint32_t reqid)
68 {
69         struct ctdb_req_header *hdr = io_elem_data(io, NULL);
70
71         hdr->length = io->len;
72         hdr->ctdb_magic = CTDB_MAGIC;
73         hdr->ctdb_version = CTDB_VERSION;
74         /* Generation and srcnode only used for inter-ctdbd communication. */
75         hdr->generation = 0;
76         hdr->destnode = destnode;
77         hdr->srcnode = 0;
78         hdr->operation = operation;
79         hdr->reqid = reqid;
80 }
81
82 /* Access to raw data: if len is non-NULL it is filled in. */
83 void *io_elem_data(const struct io_elem *io, size_t *len)
84 {
85         if (len)
86                 *len = io->len;
87         return io->data;
88 }
89
90 /* Returns -1 if we hit an error.  Errno will be set. */
91 int read_io_elem(int fd, struct io_elem *io)
92 {
93         ssize_t ret;
94
95         ret = read(fd, io->data + io->off, io->len - io->off);
96         if (ret < 0)
97                 return ret;
98
99         io->off += ret;
100         if (io_elem_finished(io)) {
101                 struct ctdb_req_header *hdr = (void *)io->data;
102
103                 /* Finished.  But maybe this was just header? */
104                 if (io->len == sizeof(*hdr) && hdr->length > io->len) {
105                         int reret;
106                         /* Enlarge and re-read. */
107                         io->len = hdr->length;
108                         io->data = realloc(io->data, io->len);
109                         if (!io->data)
110                                 return -1;
111                         /* Try reading again immediately. */
112                         reret = read_io_elem(fd, io);
113                         if (reret >= 0)
114                                 reret += ret;
115                         return reret;
116                 }
117         }
118         return ret;
119 }
120
121 /* Returns -1 if we hit an error.  Errno will be set. */
122 int write_io_elem(int fd, struct io_elem *io)
123 {
124         ssize_t ret;
125
126         ret = write(fd, io->data + io->off, io->len - io->off);
127         if (ret < 0)
128                 return ret;
129
130         io->off += ret;
131         return ret;
132 }
133
134 void io_elem_reset(struct io_elem *io)
135 {
136         io->off = 0;
137 }