Commit | Line | Data |
---|---|---|
331744e3 | 1 | /* |
ab5be9fa MJ |
2 | * Copyright (C) 2013 Julien Desfossez <jdesfossez@efficios.com> |
3 | * Copyright (C) 2013 David Goulet <dgoulet@efficios.com> | |
331744e3 | 4 | * |
ab5be9fa | 5 | * SPDX-License-Identifier: GPL-2.0-only |
331744e3 | 6 | * |
331744e3 JD |
7 | */ |
8 | ||
6c1c0768 | 9 | #define _LGPL_SOURCE |
331744e3 JD |
10 | #include <assert.h> |
11 | #include <pthread.h> | |
12 | #include <stdlib.h> | |
13 | #include <string.h> | |
14 | #include <sys/types.h> | |
15 | #include <unistd.h> | |
16 | #include <inttypes.h> | |
17 | ||
18 | #include <common/common.h> | |
19 | #include <common/utils.h> | |
20 | #include <common/sessiond-comm/sessiond-comm.h> | |
21 | #include <common/ust-consumer/ust-consumer.h> | |
c8fea79c | 22 | #include <common/consumer/consumer.h> |
331744e3 JD |
23 | |
24 | #include "consumer-metadata-cache.h" | |
25 | ||
920f2ddb JG |
26 | enum metadata_cache_update_version_status { |
27 | METADATA_CACHE_UPDATE_STATUS_VERSION_UPDATED, | |
28 | METADATA_CACHE_UPDATE_STATUS_VERSION_NOT_UPDATED, | |
29 | }; | |
30 | ||
fe81e5c9 DG |
31 | extern struct lttng_consumer_global_data consumer_data; |
32 | ||
331744e3 JD |
33 | /* |
34 | * Extend the allocated size of the metadata cache. Called only from | |
35 | * lttng_ustconsumer_write_metadata_cache. | |
36 | * | |
37 | * Return 0 on success, a negative value on error. | |
38 | */ | |
39 | static int extend_metadata_cache(struct lttng_consumer_channel *channel, | |
40 | unsigned int size) | |
41 | { | |
42 | int ret = 0; | |
43 | char *tmp_data_ptr; | |
53efb85a | 44 | unsigned int new_size, old_size; |
331744e3 JD |
45 | |
46 | assert(channel); | |
47 | assert(channel->metadata_cache); | |
48 | ||
53efb85a MD |
49 | old_size = channel->metadata_cache->cache_alloc_size; |
50 | new_size = max_t(unsigned int, old_size + size, old_size << 1); | |
331744e3 JD |
51 | DBG("Extending metadata cache to %u", new_size); |
52 | tmp_data_ptr = realloc(channel->metadata_cache->data, new_size); | |
53 | if (!tmp_data_ptr) { | |
54 | ERR("Reallocating metadata cache"); | |
55 | free(channel->metadata_cache->data); | |
56 | ret = -1; | |
57 | goto end; | |
58 | } | |
53efb85a MD |
59 | /* Zero newly allocated memory */ |
60 | memset(tmp_data_ptr + old_size, 0, new_size - old_size); | |
331744e3 JD |
61 | channel->metadata_cache->data = tmp_data_ptr; |
62 | channel->metadata_cache->cache_alloc_size = new_size; | |
63 | ||
64 | end: | |
65 | return ret; | |
66 | } | |
67 | ||
93ec662e JD |
68 | /* |
69 | * Reset the metadata cache. | |
70 | */ | |
71 | static | |
72 | void metadata_cache_reset(struct consumer_metadata_cache *cache) | |
73 | { | |
74 | memset(cache->data, 0, cache->cache_alloc_size); | |
75 | cache->max_offset = 0; | |
76 | } | |
77 | ||
78 | /* | |
79 | * Check if the metadata cache version changed. | |
80 | * If it did, reset the metadata cache. | |
81 | * The metadata cache lock MUST be held. | |
93ec662e | 82 | */ |
920f2ddb JG |
83 | static enum metadata_cache_update_version_status metadata_cache_update_version( |
84 | struct consumer_metadata_cache *cache, uint64_t version) | |
93ec662e | 85 | { |
920f2ddb | 86 | enum metadata_cache_update_version_status status; |
93ec662e JD |
87 | |
88 | if (cache->version == version) { | |
920f2ddb | 89 | status = METADATA_CACHE_UPDATE_STATUS_VERSION_NOT_UPDATED; |
93ec662e JD |
90 | goto end; |
91 | } | |
92 | ||
93 | DBG("Metadata cache version update to %" PRIu64, version); | |
93ec662e | 94 | cache->version = version; |
920f2ddb | 95 | status = METADATA_CACHE_UPDATE_STATUS_VERSION_UPDATED; |
93ec662e JD |
96 | |
97 | end: | |
920f2ddb | 98 | return status; |
5b8eb761 JD |
99 | } |
100 | ||
331744e3 JD |
101 | /* |
102 | * Write metadata to the cache, extend the cache if necessary. We support | |
c585821b MD |
103 | * overlapping updates, but they need to be contiguous. Send the |
104 | * contiguous metadata in cache to the ring buffer. The metadata cache | |
331744e3 JD |
105 | * lock MUST be acquired to write in the cache. |
106 | * | |
920f2ddb JG |
107 | * See `enum consumer_metadata_cache_write_status` for the meaning of the |
108 | * various returned status codes. | |
331744e3 | 109 | */ |
920f2ddb JG |
110 | enum consumer_metadata_cache_write_status |
111 | consumer_metadata_cache_write(struct lttng_consumer_channel *channel, | |
93ec662e JD |
112 | unsigned int offset, unsigned int len, uint64_t version, |
113 | char *data) | |
331744e3 JD |
114 | { |
115 | int ret = 0; | |
116 | struct consumer_metadata_cache *cache; | |
920f2ddb JG |
117 | enum consumer_metadata_cache_write_status status; |
118 | bool cache_is_invalidated = false; | |
119 | uint64_t original_max_offset; | |
331744e3 JD |
120 | |
121 | assert(channel); | |
122 | assert(channel->metadata_cache); | |
123 | ||
124 | cache = channel->metadata_cache; | |
920f2ddb JG |
125 | ASSERT_LOCKED(cache->lock); |
126 | original_max_offset = cache->max_offset; | |
93ec662e | 127 | |
920f2ddb JG |
128 | if (metadata_cache_update_version(cache, version) == |
129 | METADATA_CACHE_UPDATE_STATUS_VERSION_UPDATED) { | |
130 | metadata_cache_reset(cache); | |
131 | cache_is_invalidated = true; | |
93ec662e JD |
132 | } |
133 | ||
331744e3 JD |
134 | DBG("Writing %u bytes from offset %u in metadata cache", len, offset); |
135 | ||
136 | if (offset + len > cache->cache_alloc_size) { | |
137 | ret = extend_metadata_cache(channel, | |
138 | len - cache->cache_alloc_size + offset); | |
139 | if (ret < 0) { | |
140 | ERR("Extending metadata cache"); | |
920f2ddb | 141 | status = CONSUMER_METADATA_CACHE_WRITE_STATUS_ERROR; |
331744e3 JD |
142 | goto end; |
143 | } | |
144 | } | |
145 | ||
146 | memcpy(cache->data + offset, data, len); | |
920f2ddb JG |
147 | cache->max_offset = max(cache->max_offset, offset + len); |
148 | ||
149 | if (cache_is_invalidated) { | |
150 | status = CONSUMER_METADATA_CACHE_WRITE_STATUS_INVALIDATED; | |
151 | } else if (cache->max_offset > original_max_offset) { | |
152 | status = CONSUMER_METADATA_CACHE_WRITE_STATUS_APPENDED_CONTENT; | |
153 | } else { | |
154 | status = CONSUMER_METADATA_CACHE_WRITE_STATUS_NO_CHANGE; | |
155 | assert(cache->max_offset == original_max_offset); | |
331744e3 JD |
156 | } |
157 | ||
158 | end: | |
920f2ddb | 159 | return status; |
331744e3 JD |
160 | } |
161 | ||
162 | /* | |
163 | * Create the metadata cache, original allocated size: max_sb_size | |
164 | * | |
165 | * Return 0 on success, a negative value on error. | |
166 | */ | |
167 | int consumer_metadata_cache_allocate(struct lttng_consumer_channel *channel) | |
168 | { | |
169 | int ret; | |
170 | ||
171 | assert(channel); | |
172 | ||
173 | channel->metadata_cache = zmalloc( | |
174 | sizeof(struct consumer_metadata_cache)); | |
175 | if (!channel->metadata_cache) { | |
176 | PERROR("zmalloc metadata cache struct"); | |
177 | ret = -1; | |
178 | goto end; | |
179 | } | |
180 | ret = pthread_mutex_init(&channel->metadata_cache->lock, NULL); | |
181 | if (ret != 0) { | |
182 | PERROR("mutex init"); | |
183 | goto end_free_cache; | |
184 | } | |
185 | ||
186 | channel->metadata_cache->cache_alloc_size = DEFAULT_METADATA_CACHE_SIZE; | |
187 | channel->metadata_cache->data = zmalloc( | |
188 | channel->metadata_cache->cache_alloc_size * sizeof(char)); | |
189 | if (!channel->metadata_cache->data) { | |
190 | PERROR("zmalloc metadata cache data"); | |
191 | ret = -1; | |
192 | goto end_free_mutex; | |
193 | } | |
194 | DBG("Allocated metadata cache of %" PRIu64 " bytes", | |
195 | channel->metadata_cache->cache_alloc_size); | |
196 | ||
197 | ret = 0; | |
198 | goto end; | |
199 | ||
200 | end_free_mutex: | |
201 | pthread_mutex_destroy(&channel->metadata_cache->lock); | |
202 | end_free_cache: | |
203 | free(channel->metadata_cache); | |
204 | end: | |
205 | return ret; | |
206 | } | |
207 | ||
208 | /* | |
209 | * Destroy and free the metadata cache | |
210 | */ | |
211 | void consumer_metadata_cache_destroy(struct lttng_consumer_channel *channel) | |
212 | { | |
213 | if (!channel || !channel->metadata_cache) { | |
214 | return; | |
215 | } | |
216 | ||
217 | DBG("Destroying metadata cache"); | |
218 | ||
331744e3 JD |
219 | pthread_mutex_destroy(&channel->metadata_cache->lock); |
220 | free(channel->metadata_cache->data); | |
221 | free(channel->metadata_cache); | |
222 | } | |
223 | ||
224 | /* | |
225 | * Check if the cache is flushed up to the offset passed in parameter. | |
226 | * | |
227 | * Return 0 if everything has been flushed, 1 if there is data not flushed. | |
228 | */ | |
229 | int consumer_metadata_cache_flushed(struct lttng_consumer_channel *channel, | |
5e41ebe1 | 230 | uint64_t offset, int timer) |
331744e3 | 231 | { |
04ef1097 MD |
232 | int ret = 0; |
233 | struct lttng_consumer_stream *metadata_stream; | |
331744e3 JD |
234 | |
235 | assert(channel); | |
236 | assert(channel->metadata_cache); | |
237 | ||
7f725ec5 | 238 | /* |
5e41ebe1 MD |
239 | * If not called from a timer handler, we have to take the |
240 | * channel lock to be mutually exclusive with channel teardown. | |
241 | * Timer handler does not need to take this lock because it is | |
242 | * already synchronized by timer stop (and, more importantly, | |
243 | * taking this lock in a timer handler would cause a deadlock). | |
7f725ec5 | 244 | */ |
5e41ebe1 MD |
245 | if (!timer) { |
246 | pthread_mutex_lock(&channel->lock); | |
247 | } | |
ec6ea7d0 | 248 | pthread_mutex_lock(&channel->timer_lock); |
04ef1097 | 249 | metadata_stream = channel->metadata_stream; |
04ef1097 | 250 | if (!metadata_stream) { |
fe81e5c9 DG |
251 | /* |
252 | * Having no metadata stream means the channel is being destroyed so there | |
253 | * is no cache to flush anymore. | |
254 | */ | |
255 | ret = 0; | |
e524139e JG |
256 | goto end_unlock_channel; |
257 | } | |
258 | ||
259 | pthread_mutex_lock(&metadata_stream->lock); | |
260 | pthread_mutex_lock(&channel->metadata_cache->lock); | |
261 | ||
262 | if (metadata_stream->ust_metadata_pushed >= offset) { | |
04ef1097 | 263 | ret = 0; |
fe81e5c9 DG |
264 | } else if (channel->metadata_stream->endpoint_status != |
265 | CONSUMER_ENDPOINT_ACTIVE) { | |
266 | /* An inactive endpoint means we don't have to flush anymore. */ | |
267 | ret = 0; | |
331744e3 | 268 | } else { |
fe81e5c9 | 269 | /* Still not completely flushed. */ |
331744e3 JD |
270 | ret = 1; |
271 | } | |
fe81e5c9 | 272 | |
331744e3 | 273 | pthread_mutex_unlock(&channel->metadata_cache->lock); |
8e1ef46e | 274 | pthread_mutex_unlock(&metadata_stream->lock); |
e524139e | 275 | end_unlock_channel: |
ec6ea7d0 | 276 | pthread_mutex_unlock(&channel->timer_lock); |
5e41ebe1 MD |
277 | if (!timer) { |
278 | pthread_mutex_unlock(&channel->lock); | |
279 | } | |
331744e3 JD |
280 | |
281 | return ret; | |
282 | } |