Fix: support temporary snapshot max size and name
[lttng-tools.git] / src / bin / lttng-sessiond / snapshot.c
1 /*
2 * Copyright (C) 2013 - David Goulet <dgoulet@efficios.com>
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License, version 2 only, as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 *
13 * You should have received a copy of the GNU General Public License along with
14 * this program; if not, write to the Free Software Foundation, Inc., 51
15 * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
16 */
17
18 #define _GNU_SOURCE
19 #include <assert.h>
20 #include <inttypes.h>
21 #include <string.h>
22 #include <urcu/uatomic.h>
23
24 #include <common/defaults.h>
25
26 #include "snapshot.h"
27
28 /*
29 * Return the atomically incremented value of next_output_id.
30 */
31 static inline unsigned long get_next_output_id(struct snapshot *snapshot)
32 {
33 return uatomic_add_return(&snapshot->next_output_id, 1);
34 }
35
36 /*
37 * Initialized snapshot output with the given values.
38 *
39 * Return 0 on success or else a negative value.
40 */
41 static int output_init(uint64_t max_size, const char *name,
42 struct lttng_uri *uris, size_t nb_uri,
43 struct consumer_output *consumer, struct snapshot_output *output,
44 struct snapshot *snapshot)
45 {
46 int ret = 0, i;
47
48 assert(output);
49
50 if (max_size == (uint64_t) -1ULL) {
51 max_size = 0;
52 }
53 output->max_size = max_size;
54
55 if (snapshot) {
56 output->id = get_next_output_id(snapshot);
57 }
58 lttng_ht_node_init_ulong(&output->node, (unsigned long) output->id);
59
60 if (name && name[0] != '\0') {
61 strncpy(output->name, name, sizeof(output->name));
62 } else {
63 /* Set default name. */
64 ret = snprintf(output->name, sizeof(output->name), "%s-%" PRIu32,
65 DEFAULT_SNAPSHOT_NAME, output->id);
66 if (ret < 0) {
67 ret = -ENOMEM;
68 goto error;
69 }
70 }
71
72 if (!consumer) {
73 goto end;
74 }
75
76 output->consumer = consumer_copy_output(consumer);
77 if (!output->consumer) {
78 ret = -ENOMEM;
79 goto error;
80 }
81
82 /* No URL given. */
83 if (nb_uri == 0) {
84 ret = 0;
85 goto end;
86 }
87
88 if (uris[0].dtype == LTTNG_DST_PATH) {
89 memset(output->consumer->dst.trace_path, 0,
90 sizeof(output->consumer->dst.trace_path));
91 strncpy(output->consumer->dst.trace_path, uris[0].dst.path,
92 sizeof(output->consumer->dst.trace_path));
93 output->consumer->type = CONSUMER_DST_LOCAL;
94 ret = 0;
95 goto end;
96 }
97
98 if (nb_uri != 2) {
99 /* Absolutely needs two URIs for network. */
100 ret = -LTTNG_ERR_INVALID;
101 goto error;
102 }
103
104 for (i = 0; i < nb_uri; i ++) {
105 /* Network URIs */
106 ret = consumer_set_network_uri(output->consumer, &uris[i]);
107 if (ret < 0) {
108 goto error;
109 }
110 }
111
112 error:
113 end:
114 return ret;
115 }
116
117 /*
118 * Initialize a snapshot output object using the given parameters and URI(s).
119 * The name value and uris can be NULL.
120 *
121 * Return 0 on success or else a negative value.
122 */
123 int snapshot_output_init_with_uri(uint64_t max_size, const char *name,
124 struct lttng_uri *uris, size_t nb_uri,
125 struct consumer_output *consumer, struct snapshot_output *output,
126 struct snapshot *snapshot)
127 {
128 return output_init(max_size, name, uris, nb_uri, consumer, output,
129 snapshot);
130 }
131
132 /*
133 * Initialize a snapshot output object using the given parameters. The name
134 * value and url can be NULL.
135 *
136 * Return 0 on success or else a negative value.
137 */
138 int snapshot_output_init(uint64_t max_size, const char *name,
139 const char *ctrl_url, const char *data_url,
140 struct consumer_output *consumer, struct snapshot_output *output,
141 struct snapshot *snapshot)
142 {
143 int ret = 0, nb_uri;
144 struct lttng_uri *uris = NULL;
145
146 /* Create an array of URIs from URLs. */
147 nb_uri = uri_parse_str_urls(ctrl_url, data_url, &uris);
148 if (nb_uri < 0) {
149 ret = nb_uri;
150 goto error;
151 }
152
153 ret = output_init(max_size, name, uris, nb_uri, consumer, output,
154 snapshot);
155
156 error:
157 free(uris);
158 return ret;
159 }
160
161 struct snapshot_output *snapshot_output_alloc(void)
162 {
163 return zmalloc(sizeof(struct snapshot_output));
164 }
165
166 /*
167 * Delete output from the snapshot object.
168 */
169 void snapshot_delete_output(struct snapshot *snapshot,
170 struct snapshot_output *output)
171 {
172 int ret;
173 struct lttng_ht_iter iter;
174
175 assert(snapshot);
176 assert(snapshot->output_ht);
177 assert(output);
178
179 iter.iter.node = &output->node.node;
180 rcu_read_lock();
181 ret = lttng_ht_del(snapshot->output_ht, &iter);
182 rcu_read_unlock();
183 assert(!ret);
184 /*
185 * This is safe because the ownership of a snapshot object is in a session
186 * for which the session lock need to be acquired to read and modify it.
187 */
188 snapshot->nb_output--;
189 }
190
191 /*
192 * Add output object to the snapshot.
193 */
194 void snapshot_add_output(struct snapshot *snapshot,
195 struct snapshot_output *output)
196 {
197 assert(snapshot);
198 assert(snapshot->output_ht);
199 assert(output);
200
201 rcu_read_lock();
202 lttng_ht_add_unique_ulong(snapshot->output_ht, &output->node);
203 rcu_read_unlock();
204 /*
205 * This is safe because the ownership of a snapshot object is in a session
206 * for which the session lock need to be acquired to read and modify it.
207 */
208 snapshot->nb_output++;
209 }
210
211 /*
212 * Destroy and free a snapshot output object.
213 */
214 void snapshot_output_destroy(struct snapshot_output *obj)
215 {
216 assert(obj);
217
218 if (obj->consumer) {
219 consumer_output_send_destroy_relayd(obj->consumer);
220 consumer_destroy_output(obj->consumer);
221 }
222 free(obj);
223 }
224
225 /*
226 * RCU read side lock MUST be acquired before calling this since the returned
227 * pointer is in a RCU hash table.
228 *
229 * Return the reference on success or else NULL.
230 */
231 struct snapshot_output *snapshot_find_output_by_id(uint32_t id,
232 struct snapshot *snapshot)
233 {
234 struct lttng_ht_node_ulong *node;
235 struct lttng_ht_iter iter;
236 struct snapshot_output *output = NULL;
237
238 assert(snapshot);
239
240 lttng_ht_lookup(snapshot->output_ht, (void *)((unsigned long) id), &iter);
241 node = lttng_ht_iter_get_node_ulong(&iter);
242 if (!node) {
243 DBG3("Snapshot output not found with id %" PRId32, id);
244 goto error;
245 }
246 output = caa_container_of(node, struct snapshot_output, node);
247
248 error:
249 return output;
250 }
251
252 /*
253 * Initialized a snapshot object that was already allocated.
254 *
255 * Return 0 on success or else a negative errno value.
256 */
257 int snapshot_init(struct snapshot *obj)
258 {
259 int ret;
260
261 assert(obj);
262
263 memset(obj, 0, sizeof(struct snapshot));
264
265 obj->output_ht = lttng_ht_new(0, LTTNG_HT_TYPE_ULONG);
266 if (!obj->output_ht) {
267 ret = -ENOMEM;
268 goto error;
269 }
270
271 ret = 0;
272
273 error:
274 return ret;
275 }
276
277 /*
278 * Destroy snapshot object but the pointer is not freed so it's safe to pass a
279 * static reference.
280 */
281 void snapshot_destroy(struct snapshot *obj)
282 {
283 struct lttng_ht_iter iter;
284 struct snapshot_output *output;
285
286 assert(obj);
287
288 rcu_read_lock();
289 cds_lfht_for_each_entry(obj->output_ht->ht, &iter.iter, output,
290 node.node) {
291 snapshot_delete_output(obj, output);
292 snapshot_output_destroy(output);
293 }
294 rcu_read_unlock();
295 }
This page took 0.036834 seconds and 4 git commands to generate.