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;
/*
* 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? */
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;
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)
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);
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;
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;
}
*
* 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;
}
}
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(