2 * Copyright (C) 2013 - Julien Desfossez <jdesfossez@efficios.com>
3 * David Goulet <dgoulet@efficios.com>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License, version 2 only,
7 * as published by the Free Software Foundation.
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 #include <sys/types.h>
28 #include <common/common.h>
29 #include <common/utils.h>
30 #include <common/sessiond-comm/sessiond-comm.h>
31 #include <common/ust-consumer/ust-consumer.h>
32 #include <common/consumer/consumer.h>
34 #include "consumer-metadata-cache.h"
36 enum metadata_cache_update_version_status
{
37 METADATA_CACHE_UPDATE_STATUS_VERSION_UPDATED
,
38 METADATA_CACHE_UPDATE_STATUS_VERSION_NOT_UPDATED
,
41 extern struct lttng_consumer_global_data consumer_data
;
44 * Extend the allocated size of the metadata cache. Called only from
45 * lttng_ustconsumer_write_metadata_cache.
47 * Return 0 on success, a negative value on error.
49 static int extend_metadata_cache(struct lttng_consumer_channel
*channel
,
54 unsigned int new_size
, old_size
;
57 assert(channel
->metadata_cache
);
59 old_size
= channel
->metadata_cache
->cache_alloc_size
;
60 new_size
= max_t(unsigned int, old_size
+ size
, old_size
<< 1);
61 DBG("Extending metadata cache to %u", new_size
);
62 tmp_data_ptr
= realloc(channel
->metadata_cache
->data
, new_size
);
64 ERR("Reallocating metadata cache");
65 free(channel
->metadata_cache
->data
);
69 /* Zero newly allocated memory */
70 memset(tmp_data_ptr
+ old_size
, 0, new_size
- old_size
);
71 channel
->metadata_cache
->data
= tmp_data_ptr
;
72 channel
->metadata_cache
->cache_alloc_size
= new_size
;
79 * Reset the metadata cache.
82 void metadata_cache_reset(struct consumer_metadata_cache
*cache
)
84 memset(cache
->data
, 0, cache
->cache_alloc_size
);
85 cache
->max_offset
= 0;
89 * Check if the metadata cache version changed.
90 * If it did, reset the metadata cache.
91 * The metadata cache lock MUST be held.
93 static enum metadata_cache_update_version_status
metadata_cache_update_version(
94 struct consumer_metadata_cache
*cache
, uint64_t version
)
96 enum metadata_cache_update_version_status status
;
98 if (cache
->version
== version
) {
99 status
= METADATA_CACHE_UPDATE_STATUS_VERSION_NOT_UPDATED
;
103 DBG("Metadata cache version update to %" PRIu64
, version
);
104 cache
->version
= version
;
105 status
= METADATA_CACHE_UPDATE_STATUS_VERSION_UPDATED
;
112 * Write metadata to the cache, extend the cache if necessary. We support
113 * overlapping updates, but they need to be contiguous. Send the
114 * contiguous metadata in cache to the ring buffer. The metadata cache
115 * lock MUST be acquired to write in the cache.
117 * See `enum consumer_metadata_cache_write_status` for the meaning of the
118 * various returned status codes.
120 enum consumer_metadata_cache_write_status
121 consumer_metadata_cache_write(struct lttng_consumer_channel
*channel
,
122 unsigned int offset
, unsigned int len
, uint64_t version
,
126 struct consumer_metadata_cache
*cache
;
127 enum consumer_metadata_cache_write_status status
;
128 bool cache_is_invalidated
= false;
129 uint64_t original_max_offset
;
132 assert(channel
->metadata_cache
);
134 cache
= channel
->metadata_cache
;
135 ASSERT_LOCKED(cache
->lock
);
136 original_max_offset
= cache
->max_offset
;
138 if (metadata_cache_update_version(cache
, version
) ==
139 METADATA_CACHE_UPDATE_STATUS_VERSION_UPDATED
) {
140 metadata_cache_reset(cache
);
141 cache_is_invalidated
= true;
144 DBG("Writing %u bytes from offset %u in metadata cache", len
, offset
);
146 if (offset
+ len
> cache
->cache_alloc_size
) {
147 ret
= extend_metadata_cache(channel
,
148 len
- cache
->cache_alloc_size
+ offset
);
150 ERR("Extending metadata cache");
151 status
= CONSUMER_METADATA_CACHE_WRITE_STATUS_ERROR
;
156 memcpy(cache
->data
+ offset
, data
, len
);
157 cache
->max_offset
= max(cache
->max_offset
, offset
+ len
);
159 if (cache_is_invalidated
) {
160 status
= CONSUMER_METADATA_CACHE_WRITE_STATUS_INVALIDATED
;
161 } else if (cache
->max_offset
> original_max_offset
) {
162 status
= CONSUMER_METADATA_CACHE_WRITE_STATUS_APPENDED_CONTENT
;
164 status
= CONSUMER_METADATA_CACHE_WRITE_STATUS_NO_CHANGE
;
165 assert(cache
->max_offset
== original_max_offset
);
173 * Create the metadata cache, original allocated size: max_sb_size
175 * Return 0 on success, a negative value on error.
177 int consumer_metadata_cache_allocate(struct lttng_consumer_channel
*channel
)
183 channel
->metadata_cache
= zmalloc(
184 sizeof(struct consumer_metadata_cache
));
185 if (!channel
->metadata_cache
) {
186 PERROR("zmalloc metadata cache struct");
190 ret
= pthread_mutex_init(&channel
->metadata_cache
->lock
, NULL
);
192 PERROR("mutex init");
196 channel
->metadata_cache
->cache_alloc_size
= DEFAULT_METADATA_CACHE_SIZE
;
197 channel
->metadata_cache
->data
= zmalloc(
198 channel
->metadata_cache
->cache_alloc_size
* sizeof(char));
199 if (!channel
->metadata_cache
->data
) {
200 PERROR("zmalloc metadata cache data");
204 DBG("Allocated metadata cache of %" PRIu64
" bytes",
205 channel
->metadata_cache
->cache_alloc_size
);
211 pthread_mutex_destroy(&channel
->metadata_cache
->lock
);
213 free(channel
->metadata_cache
);
219 * Destroy and free the metadata cache
221 void consumer_metadata_cache_destroy(struct lttng_consumer_channel
*channel
)
223 if (!channel
|| !channel
->metadata_cache
) {
227 DBG("Destroying metadata cache");
229 pthread_mutex_destroy(&channel
->metadata_cache
->lock
);
230 free(channel
->metadata_cache
->data
);
231 free(channel
->metadata_cache
);
235 * Check if the cache is flushed up to the offset passed in parameter.
237 * Return 0 if everything has been flushed, 1 if there is data not flushed.
239 int consumer_metadata_cache_flushed(struct lttng_consumer_channel
*channel
,
240 uint64_t offset
, int timer
)
243 struct lttng_consumer_stream
*metadata_stream
;
246 assert(channel
->metadata_cache
);
249 * If not called from a timer handler, we have to take the
250 * channel lock to be mutually exclusive with channel teardown.
251 * Timer handler does not need to take this lock because it is
252 * already synchronized by timer stop (and, more importantly,
253 * taking this lock in a timer handler would cause a deadlock).
256 pthread_mutex_lock(&channel
->lock
);
258 pthread_mutex_lock(&channel
->timer_lock
);
259 metadata_stream
= channel
->metadata_stream
;
260 if (!metadata_stream
) {
262 * Having no metadata stream means the channel is being destroyed so there
263 * is no cache to flush anymore.
266 goto end_unlock_channel
;
269 pthread_mutex_lock(&metadata_stream
->lock
);
270 pthread_mutex_lock(&channel
->metadata_cache
->lock
);
272 if (metadata_stream
->ust_metadata_pushed
>= offset
) {
274 } else if (channel
->metadata_stream
->endpoint_status
!=
275 CONSUMER_ENDPOINT_ACTIVE
) {
276 /* An inactive endpoint means we don't have to flush anymore. */
279 /* Still not completely flushed. */
283 pthread_mutex_unlock(&channel
->metadata_cache
->lock
);
284 pthread_mutex_unlock(&metadata_stream
->lock
);
286 pthread_mutex_unlock(&channel
->timer_lock
);
288 pthread_mutex_unlock(&channel
->lock
);