X-Git-Url: https://git.lttng.org/?a=blobdiff_plain;f=src%2Fcommon%2Ftrace-chunk.c;h=bed6b73afb5d7cd79b3fab13552cb5d75a7df808;hb=159138d3dbee3c158b16f9c350a39659ed696745;hp=29977cabb1ae48e7ab015e717dc38173fcfd93d8;hpb=9c38b76fa6bba451f810ab123982a8d7aa4eb29a;p=lttng-tools.git diff --git a/src/common/trace-chunk.c b/src/common/trace-chunk.c index 29977cabb..bed6b73af 100644 --- a/src/common/trace-chunk.c +++ b/src/common/trace-chunk.c @@ -66,6 +66,7 @@ struct chunk_credentials { struct lttng_credentials user; }; +/* NOTE: Make sure to update lttng_trace_chunk_copy if you modify this. */ struct lttng_trace_chunk { pthread_mutex_t lock; struct urcu_ref ref; @@ -73,6 +74,8 @@ struct lttng_trace_chunk { /* * First-level directories created within the trace chunk. * Elements are of type 'char *'. + * + * Only used by _owner_ mode chunks. */ struct lttng_dynamic_pointer_array top_level_directories; /* Is contained within an lttng_trace_chunk_registry_element? */ @@ -81,8 +84,14 @@ struct lttng_trace_chunk { char *name; /* An unset id means the chunk is anonymous. */ LTTNG_OPTIONAL(uint64_t) id; + + /* + * The creation and close timestamps are NOT monotonic. + * They must not be used in context were monotonicity is required. + */ LTTNG_OPTIONAL(time_t) timestamp_creation; LTTNG_OPTIONAL(time_t) timestamp_close; + LTTNG_OPTIONAL(struct chunk_credentials) credentials; LTTNG_OPTIONAL(struct lttng_directory_handle) session_output_directory; LTTNG_OPTIONAL(struct lttng_directory_handle) chunk_directory; @@ -104,11 +113,13 @@ struct lttng_trace_chunk_registry { struct cds_lfht *ht; }; -const char *close_command_names[] = { +static const +char *close_command_names[] = { [LTTNG_TRACE_CHUNK_COMMAND_TYPE_MOVE_TO_COMPLETED] = "move to completed chunk folder", }; +static const chunk_close_command close_command_funcs[] = { [LTTNG_TRACE_CHUNK_COMMAND_TYPE_MOVE_TO_COMPLETED] = lttng_trace_chunk_move_to_completed, @@ -300,6 +311,72 @@ error: return NULL; } +LTTNG_HIDDEN +struct lttng_trace_chunk *lttng_trace_chunk_copy( + struct lttng_trace_chunk *source_chunk) +{ + struct lttng_trace_chunk *new_chunk = lttng_trace_chunk_allocate(); + + if (!new_chunk) { + goto end; + } + + pthread_mutex_lock(&source_chunk->lock); + /* + * A new chunk is always a user; it shall create no new trace + * subdirectories. + */ + new_chunk->mode = (typeof(new_chunk->mode)) { + .is_set = true, + .value = TRACE_CHUNK_MODE_USER, + }; + /* + * top_level_directories is not copied as it is never used + * by _user_ mode chunks. + */ + /* The new chunk is not part of a registry (yet, at least). */ + new_chunk->in_registry_element = false; + new_chunk->name_overridden = source_chunk->name_overridden; + if (source_chunk->name) { + new_chunk->name = strdup(source_chunk->name); + if (!new_chunk->name) { + ERR("Failed to copy source trace chunk name in %s()", + __FUNCTION__); + goto error_unlock; + } + } + new_chunk->id = source_chunk->id; + new_chunk->timestamp_creation = source_chunk->timestamp_creation; + new_chunk->timestamp_close = source_chunk->timestamp_close; + new_chunk->credentials = source_chunk->credentials; + if (source_chunk->session_output_directory.is_set) { + if (lttng_directory_handle_copy( + &source_chunk->session_output_directory.value, + &new_chunk->session_output_directory.value)) { + goto error_unlock; + } else { + new_chunk->session_output_directory.is_set = true; + } + } + if (source_chunk->chunk_directory.is_set) { + if (lttng_directory_handle_copy( + &source_chunk->chunk_directory.value, + &new_chunk->chunk_directory.value)) { + goto error_unlock; + } else { + new_chunk->chunk_directory.is_set = true; + } + } + new_chunk->close_command = source_chunk->close_command; + pthread_mutex_unlock(&source_chunk->lock); +end: + return new_chunk; +error_unlock: + pthread_mutex_unlock(&source_chunk->lock); + lttng_trace_chunk_put(new_chunk); + return NULL; +} + LTTNG_HIDDEN enum lttng_trace_chunk_status lttng_trace_chunk_get_id( struct lttng_trace_chunk *chunk, uint64_t *id) @@ -361,11 +438,20 @@ enum lttng_trace_chunk_status lttng_trace_chunk_set_close_timestamp( status = LTTNG_TRACE_CHUNK_STATUS_INVALID_OPERATION; goto end; } + + /* + * Note: we do not enforce that the closing timestamp be greater or + * equal to the begin timestamp. These timestamps are used for + * generating the chunk name and should only be used in context where + * the monotonicity of time is not important. The source of those + * timestamps is NOT monotonic and represent the system calendar time, + * also know as the wall time. + */ if (chunk->timestamp_creation.value > close_ts) { - ERR("Failed to set trace chunk close timestamp: close timestamp is before creation timestamp"); - status = LTTNG_TRACE_CHUNK_STATUS_INVALID_ARGUMENT; - goto end; + WARN("Set trace chunk close timestamp: close timestamp is before creation timestamp, begin : %ld, close : %ld", + chunk->timestamp_creation.value, close_ts); } + LTTNG_OPTIONAL_SET(&chunk->timestamp_close, close_ts); if (!chunk->name_overridden) { free(chunk->name); @@ -769,7 +855,7 @@ enum lttng_trace_chunk_status lttng_trace_chunk_open_file( chunk->credentials.value.use_current_user ? NULL : &chunk->credentials.value.user); if (ret < 0) { - ERR("Failed to open file relative to trace chunk file_path = \"%s\", flags = %d, mode = %d", + PERROR("Failed to open file relative to trace chunk file_path = \"%s\", flags = %d, mode = %d", file_path, flags, (int) mode); status = LTTNG_TRACE_CHUNK_STATUS_ERROR; goto end; @@ -904,6 +990,7 @@ void lttng_trace_chunk_move_to_completed(struct lttng_trace_chunk *trace_chunk) creation_timestamp, NULL); if (!directory_to_rename) { ERR("Failed to generate initial trace chunk name while renaming trace chunk"); + goto end; } free_directory_to_rename = true; } @@ -1197,7 +1284,7 @@ lttng_trace_chunk_registry_publish_chunk( * * Re-attempt to publish. */ - ERR("Attemp to publish a trace chunk to the chunk registry raced with a trace chunk deletion"); + ERR("Attempt to publish a trace chunk to the chunk registry raced with a trace chunk deletion"); continue; } } @@ -1287,6 +1374,41 @@ lttng_trace_chunk_registry_find_chunk( session_id, &chunk_id); } +LTTNG_HIDDEN +int lttng_trace_chunk_registry_chunk_exists( + const struct lttng_trace_chunk_registry *registry, + uint64_t session_id, uint64_t chunk_id, bool *chunk_exists) +{ + int ret = 0; + const struct lttng_trace_chunk_registry_element target_element = { + .chunk.id.is_set = true, + .chunk.id.value = chunk_id, + .session_id = session_id, + }; + const unsigned long element_hash = + lttng_trace_chunk_registry_element_hash( + &target_element); + struct cds_lfht_node *published_node; + struct cds_lfht_iter iter; + + rcu_read_lock(); + cds_lfht_lookup(registry->ht, + element_hash, + lttng_trace_chunk_registry_element_match, + &target_element, + &iter); + published_node = cds_lfht_iter_get_node(&iter); + if (!published_node) { + *chunk_exists = false; + goto end; + } + + *chunk_exists = !cds_lfht_is_node_deleted(published_node); +end: + rcu_read_unlock(); + return ret; +} + LTTNG_HIDDEN struct lttng_trace_chunk * lttng_trace_chunk_registry_find_anonymous_chunk(