common trace-chunk: introduce lttng_trace_chunk_get_name_overridden
[lttng-tools.git] / src / common / trace-chunk.c
index 488d7ebc4ffffcf19938cdb5f1da4036311417e6..c549f46b33c855334814355ef8a6e37f6cacadf2 100644 (file)
@@ -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,26 +74,33 @@ 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;
+       /*
+        * All files contained within the trace chunk.
+        * Array of paths (char *).
+        */
+       struct lttng_dynamic_pointer_array files;
        /* Is contained within an lttng_trace_chunk_registry_element? */
        bool in_registry_element;
-       bool name_overriden;
+       bool name_overridden;
        char *name;
        /* An unset id means the chunk is anonymous. */
        LTTNG_OPTIONAL(uint64_t) id;
        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;
+       struct lttng_directory_handle *session_output_directory;
+       struct lttng_directory_handle *chunk_directory;
        LTTNG_OPTIONAL(enum lttng_trace_chunk_command_type) close_command;
 };
 
 /* A trace chunk is uniquely identified by its (session id, chunk id) tuple. */
 struct lttng_trace_chunk_registry_element {
-       uint64_t session_id;
        struct lttng_trace_chunk chunk;
+       uint64_t session_id;
        /* Weak and only set when added. */
        struct lttng_trace_chunk_registry *registry;
        struct cds_lfht_node trace_chunk_registry_ht_node;
@@ -104,11 +112,17 @@ 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",
+       [LTTNG_TRACE_CHUNK_COMMAND_TYPE_NO_OPERATION] =
+               "no operation",
+       [LTTNG_TRACE_CHUNK_COMMAND_TYPE_DELETE] =
+               "delete",
 };
 
+static const
 chunk_close_command close_command_funcs[] = {
        [LTTNG_TRACE_CHUNK_COMMAND_TYPE_MOVE_TO_COMPLETED] =
                        lttng_trace_chunk_move_to_completed,
@@ -165,8 +179,9 @@ char *generate_chunk_name(uint64_t chunk_id, time_t creation_timestamp,
 {
        int ret = 0;
        char *new_name= NULL;
-       char start_datetime[sizeof("YYYYmmddTHHMMSS+HHMM")] = {};
-       char end_datetime_suffix[sizeof("-YYYYmmddTHHMMSS+HHMM")] = {};
+       char start_datetime[ISO8601_STR_LEN] = {};
+       /* Add 1 for a '-' prefix. */
+       char end_datetime_suffix[ISO8601_STR_LEN + 1] = {};
 
        ret = time_to_iso8601_str(
                        creation_timestamp,
@@ -180,7 +195,7 @@ char *generate_chunk_name(uint64_t chunk_id, time_t creation_timestamp,
                ret = time_to_iso8601_str(
                                *close_timestamp,
                                end_datetime_suffix + 1,
-                               sizeof(end_datetime_suffix));
+                               sizeof(end_datetime_suffix) - 1);
                if (ret) {
                        ERR("Failed to format trace chunk end date time");
                        goto error;
@@ -210,21 +225,25 @@ void lttng_trace_chunk_init(struct lttng_trace_chunk *chunk)
        urcu_ref_init(&chunk->ref);
        pthread_mutex_init(&chunk->lock, NULL);
        lttng_dynamic_pointer_array_init(&chunk->top_level_directories, free);
+       lttng_dynamic_pointer_array_init(&chunk->files, free);
 }
 
 static
 void lttng_trace_chunk_fini(struct lttng_trace_chunk *chunk)
 {
-       if (chunk->session_output_directory.is_set) {
-               lttng_directory_handle_fini(
-                               &chunk->session_output_directory.value);
+       if (chunk->session_output_directory) {
+               lttng_directory_handle_put(
+                               chunk->session_output_directory);
+               chunk->session_output_directory = NULL;
        }
-       if (chunk->chunk_directory.is_set) {
-               lttng_directory_handle_fini(&chunk->chunk_directory.value);
+       if (chunk->chunk_directory) {
+               lttng_directory_handle_put(chunk->chunk_directory);
+               chunk->chunk_directory = NULL;
        }
        free(chunk->name);
        chunk->name = NULL;
        lttng_dynamic_pointer_array_reset(&chunk->top_level_directories);
+       lttng_dynamic_pointer_array_reset(&chunk->files);
        pthread_mutex_destroy(&chunk->lock);
 }
 
@@ -299,6 +318,69 @@ 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) {
+               const bool reference_acquired = lttng_directory_handle_get(
+                               source_chunk->session_output_directory);
+
+               assert(reference_acquired);
+               new_chunk->session_output_directory =
+                               source_chunk->session_output_directory;
+       }
+       if (source_chunk->chunk_directory) {
+               const bool reference_acquired = lttng_directory_handle_get(
+                               source_chunk->chunk_directory);
+
+               assert(reference_acquired);
+               new_chunk->chunk_directory = source_chunk->chunk_directory;
+       }
+       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)
@@ -366,12 +448,14 @@ enum lttng_trace_chunk_status lttng_trace_chunk_set_close_timestamp(
                goto end;
        }
        LTTNG_OPTIONAL_SET(&chunk->timestamp_close, close_ts);
-       free(chunk->name);
-       chunk->name = generate_chunk_name(LTTNG_OPTIONAL_GET(chunk->id),
-                       LTTNG_OPTIONAL_GET(chunk->timestamp_creation),
-                       &close_ts);
-       if (!chunk->name) {
-               status = LTTNG_TRACE_CHUNK_STATUS_ERROR;
+       if (!chunk->name_overridden) {
+               free(chunk->name);
+               chunk->name = generate_chunk_name(LTTNG_OPTIONAL_GET(chunk->id),
+                               LTTNG_OPTIONAL_GET(chunk->timestamp_creation),
+                               &close_ts);
+               if (!chunk->name) {
+                       status = LTTNG_TRACE_CHUNK_STATUS_ERROR;
+               }
        }
 end:
        pthread_mutex_unlock(&chunk->lock);
@@ -381,13 +465,13 @@ end:
 LTTNG_HIDDEN
 enum lttng_trace_chunk_status lttng_trace_chunk_get_name(
                struct lttng_trace_chunk *chunk, const char **name,
-               bool *name_overriden)
+               bool *name_overridden)
 {
        enum lttng_trace_chunk_status status = LTTNG_TRACE_CHUNK_STATUS_OK;
 
        pthread_mutex_lock(&chunk->lock);
-        if (name_overriden) {
-               *name_overriden = chunk->name_overriden;
+        if (name_overridden) {
+               *name_overridden = chunk->name_overridden;
         }
         if (!chunk->name) {
                status = LTTNG_TRACE_CHUNK_STATUS_NONE;
@@ -399,6 +483,17 @@ end:
        return status;
 }
 
+LTTNG_HIDDEN
+bool lttng_trace_chunk_get_name_overridden(struct lttng_trace_chunk *chunk)
+{
+       bool name_overridden;
+
+       pthread_mutex_lock(&chunk->lock);
+       name_overridden = chunk->name_overridden;
+       pthread_mutex_unlock(&chunk->lock);
+       return name_overridden;
+}
+
 static
 bool is_valid_chunk_name(const char *name)
 {
@@ -408,7 +503,7 @@ bool is_valid_chunk_name(const char *name)
                return false;
        }
 
-       len = strnlen(name, LTTNG_NAME_MAX);
+       len = lttng_strnlen(name, LTTNG_NAME_MAX);
        if (len == 0 || len == LTTNG_NAME_MAX) {
                return false;
        }
@@ -450,7 +545,7 @@ enum lttng_trace_chunk_status lttng_trace_chunk_override_name(
        }
        free(chunk->name);
        chunk->name = new_name;
-       chunk->name_overriden = true;
+       chunk->name_overridden = true;
 end_unlock:    
        pthread_mutex_unlock(&chunk->lock);
 end:
@@ -529,7 +624,8 @@ enum lttng_trace_chunk_status lttng_trace_chunk_set_as_owner(
 {
        int ret;
        enum lttng_trace_chunk_status status = LTTNG_TRACE_CHUNK_STATUS_OK;
-       struct lttng_directory_handle chunk_directory_handle;
+       struct lttng_directory_handle *chunk_directory_handle = NULL;
+       bool reference_acquired;
 
        pthread_mutex_lock(&chunk->lock);
        if (chunk->mode.is_set) {
@@ -564,18 +660,20 @@ enum lttng_trace_chunk_status lttng_trace_chunk_set_as_owner(
                        goto end;
                }
        }
-       ret = lttng_directory_handle_init_from_handle(&chunk_directory_handle,
+       chunk_directory_handle = lttng_directory_handle_create_from_handle(
                        chunk->name,
                        session_output_directory);
-       if (ret) {
+       if (!chunk_directory_handle) {
                /* The function already logs on all error paths. */
                status = LTTNG_TRACE_CHUNK_STATUS_ERROR;
                goto end;
        }
-       LTTNG_OPTIONAL_SET(&chunk->session_output_directory,
-                       lttng_directory_handle_move(session_output_directory));
-       LTTNG_OPTIONAL_SET(&chunk->chunk_directory,
-                       lttng_directory_handle_move(&chunk_directory_handle));
+       chunk->chunk_directory = chunk_directory_handle;
+       chunk_directory_handle = NULL;
+       reference_acquired = lttng_directory_handle_get(
+                       session_output_directory);
+       assert(reference_acquired);
+       chunk->session_output_directory = session_output_directory;
        LTTNG_OPTIONAL_SET(&chunk->mode, TRACE_CHUNK_MODE_OWNER);
 end:
        pthread_mutex_unlock(&chunk->lock);
@@ -588,6 +686,7 @@ enum lttng_trace_chunk_status lttng_trace_chunk_set_as_user(
                struct lttng_directory_handle *chunk_directory)
 {
        enum lttng_trace_chunk_status status = LTTNG_TRACE_CHUNK_STATUS_OK;
+       bool reference_acquired;
 
        pthread_mutex_lock(&chunk->lock);
        if (chunk->mode.is_set) {
@@ -599,8 +698,9 @@ enum lttng_trace_chunk_status lttng_trace_chunk_set_as_user(
                status = LTTNG_TRACE_CHUNK_STATUS_ERROR;
                goto end;
        }
-       LTTNG_OPTIONAL_SET(&chunk->chunk_directory,
-                       lttng_directory_handle_move(chunk_directory));
+       reference_acquired = lttng_directory_handle_get(chunk_directory);
+       assert(reference_acquired);
+       chunk->chunk_directory = chunk_directory;
        LTTNG_OPTIONAL_SET(&chunk->mode, TRACE_CHUNK_MODE_USER);
 end:
        pthread_mutex_unlock(&chunk->lock);
@@ -608,19 +708,19 @@ end:
 }
 
 LTTNG_HIDDEN
-enum lttng_trace_chunk_status lttng_trace_chunk_get_chunk_directory_handle(
+enum lttng_trace_chunk_status lttng_trace_chunk_borrow_chunk_directory_handle(
                struct lttng_trace_chunk *chunk,
                const struct lttng_directory_handle **handle)
 {
        enum lttng_trace_chunk_status status = LTTNG_TRACE_CHUNK_STATUS_OK;
 
        pthread_mutex_lock(&chunk->lock);
-       if (!chunk->chunk_directory.is_set) {
+       if (!chunk->chunk_directory) {
                status = LTTNG_TRACE_CHUNK_STATUS_NONE;
                goto end;
        }
 
-       *handle = &chunk->chunk_directory.value;
+       *handle = chunk->chunk_directory;
 end:
        pthread_mutex_unlock(&chunk->lock);
        return status;
@@ -654,7 +754,7 @@ int add_top_level_directory_unique(struct lttng_trace_chunk *chunk,
        }
 
        if (!found) {
-               char *copy = strndup(new_path, new_path_top_level_len);
+               char *copy = lttng_strndup(new_path, new_path_top_level_len);
 
                DBG("Adding new top-level directory \"%s\" to trace chunk \"%s\"",
                                new_path, chunk->name ? : "(unnamed)");
@@ -702,7 +802,7 @@ enum lttng_trace_chunk_status lttng_trace_chunk_create_subdirectory(
                status = LTTNG_TRACE_CHUNK_STATUS_INVALID_OPERATION;
                goto end;
        }
-       if (!chunk->chunk_directory.is_set) {
+       if (!chunk->chunk_directory) {
                ERR("Attempted to create trace chunk subdirectory \"%s\" before setting the chunk output directory",
                                path);
                status = LTTNG_TRACE_CHUNK_STATUS_ERROR;
@@ -715,7 +815,7 @@ enum lttng_trace_chunk_status lttng_trace_chunk_create_subdirectory(
                goto end;
        }
        ret = lttng_directory_handle_create_subdirectory_recursive_as_user(
-                       &chunk->chunk_directory.value, path,
+                       chunk->chunk_directory, path,
                        DIR_CREATION_MODE,
                        chunk->credentials.value.use_current_user ?
                                        NULL : &chunk->credentials.value.user);
@@ -735,10 +835,84 @@ end:
        return status;
 }
 
+/*
+ * TODO: Implement O(1) lookup.
+ */
+static
+bool lttng_trace_chunk_find_file(struct lttng_trace_chunk *chunk,
+               const char *path, size_t *index)
+{
+       size_t i, count;
+
+       count = lttng_dynamic_pointer_array_get_count(&chunk->files);
+       for (i = 0; i < count; i++) {
+               const char *iter_path =
+                               lttng_dynamic_pointer_array_get_pointer(
+                                       &chunk->files, i);
+               if (!strcmp(iter_path, path)) {
+                       if (index) {
+                               *index = i;
+                       }
+                       return true;
+               }
+       }
+       return false;
+}
+
+static
+enum lttng_trace_chunk_status lttng_trace_chunk_add_file(
+               struct lttng_trace_chunk *chunk,
+               const char *path)
+{
+       char *copy;
+       int ret;
+       enum lttng_trace_chunk_status status = LTTNG_TRACE_CHUNK_STATUS_OK;
+
+       if (lttng_trace_chunk_find_file(chunk, path, NULL)) {
+               return LTTNG_TRACE_CHUNK_STATUS_OK;
+       }
+       DBG("Adding new file \"%s\" to trace chunk \"%s\"",
+                       path, chunk->name ? : "(unnamed)");
+       copy = strdup(path);
+       if (!copy) {
+               PERROR("Failed to copy path");
+               status = LTTNG_TRACE_CHUNK_STATUS_ERROR;
+               goto end;
+       }
+       ret = lttng_dynamic_pointer_array_add_pointer(
+                       &chunk->files, copy);
+       if (ret) {
+               ERR("Allocation failure while adding file to a trace chunk");
+               free(copy);
+               status = LTTNG_TRACE_CHUNK_STATUS_ERROR;
+               goto end;
+       }
+end:
+       return status;
+}
+
+static
+void lttng_trace_chunk_remove_file(
+               struct lttng_trace_chunk *chunk,
+               const char *path)
+{
+       size_t index;
+       bool found;
+       int ret;
+
+       found = lttng_trace_chunk_find_file(chunk, path, &index);
+       if (!found) {
+               return;
+       }
+       ret = lttng_dynamic_pointer_array_remove_pointer(
+                       &chunk->files, index);
+       assert(!ret);
+}
+
 LTTNG_HIDDEN
 enum lttng_trace_chunk_status lttng_trace_chunk_open_file(
                struct lttng_trace_chunk *chunk, const char *file_path,
-               int flags, mode_t mode, int *out_fd)
+               int flags, mode_t mode, int *out_fd, bool expect_no_file)
 {
        int ret;
        enum lttng_trace_chunk_status status = LTTNG_TRACE_CHUNK_STATUS_OK;
@@ -755,20 +929,29 @@ enum lttng_trace_chunk_status lttng_trace_chunk_open_file(
                status = LTTNG_TRACE_CHUNK_STATUS_ERROR;
                goto end;
        }
-       if (!chunk->chunk_directory.is_set) {
+       if (!chunk->chunk_directory) {
                ERR("Attempted to open trace chunk file \"%s\" before setting the chunk output directory",
                                file_path);
                status = LTTNG_TRACE_CHUNK_STATUS_ERROR;
                goto end;
        }
+       status = lttng_trace_chunk_add_file(chunk, file_path);
+       if (status != LTTNG_TRACE_CHUNK_STATUS_OK) {
+               goto end;
+       }
        ret = lttng_directory_handle_open_file_as_user(
-                       &chunk->chunk_directory.value, file_path, flags, mode,
+                       chunk->chunk_directory, file_path, flags, mode,
                        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",
+               if (errno == ENOENT && expect_no_file) {
+                       status = LTTNG_TRACE_CHUNK_STATUS_NO_FILE;
+               } else {
+                       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;
+                       status = LTTNG_TRACE_CHUNK_STATUS_ERROR;
+               }
+               lttng_trace_chunk_remove_file(chunk, file_path);
                goto end;
        }
        *out_fd = ret;
@@ -796,20 +979,21 @@ int lttng_trace_chunk_unlink_file(struct lttng_trace_chunk *chunk,
                status = LTTNG_TRACE_CHUNK_STATUS_ERROR;
                goto end;
        }
-       if (!chunk->chunk_directory.is_set) {
+       if (!chunk->chunk_directory) {
                ERR("Attempted to unlink trace chunk file \"%s\" before setting the chunk output directory",
                                file_path);
                status = LTTNG_TRACE_CHUNK_STATUS_ERROR;
                goto end;
        }
        ret = lttng_directory_handle_unlink_file_as_user(
-                       &chunk->chunk_directory.value, file_path,
+                       chunk->chunk_directory, file_path,
                        chunk->credentials.value.use_current_user ?
                                        NULL : &chunk->credentials.value.user);
        if (ret < 0) {
                status = LTTNG_TRACE_CHUNK_STATUS_ERROR;
                goto end;
        }
+       lttng_trace_chunk_remove_file(chunk, file_path);
 end:
        pthread_mutex_unlock(&chunk->lock);
        return status;
@@ -827,11 +1011,20 @@ void lttng_trace_chunk_move_to_completed(struct lttng_trace_chunk *trace_chunk)
                        LTTNG_OPTIONAL_GET(trace_chunk->timestamp_creation);
        const time_t close_timestamp =
                        LTTNG_OPTIONAL_GET(trace_chunk->timestamp_close);
-       LTTNG_OPTIONAL(struct lttng_directory_handle) archived_chunks_directory;
+       struct lttng_directory_handle *archived_chunks_directory = NULL;
+
+       if (!trace_chunk->mode.is_set ||
+                       trace_chunk->mode.value != TRACE_CHUNK_MODE_OWNER ||
+                       !trace_chunk->session_output_directory) {
+               /*
+                * This command doesn't need to run if the output is remote
+                * or if the trace chunk is not owned by this process.
+                */
+               goto end;
+       }
 
-       assert(trace_chunk->mode.is_set);
        assert(trace_chunk->mode.value == TRACE_CHUNK_MODE_OWNER);
-       assert(!trace_chunk->name_overriden);
+       assert(!trace_chunk->name_overridden);
 
        /*
         * The fist trace chunk of a session is directly output to the
@@ -840,12 +1033,13 @@ void lttng_trace_chunk_move_to_completed(struct lttng_trace_chunk *trace_chunk)
         * is renamed to match the chunk's name.
         */
        if (chunk_id == 0) {
-               struct lttng_directory_handle temporary_rename_directory;
+               struct lttng_directory_handle *temporary_rename_directory =
+                               NULL;
                size_t i, count = lttng_dynamic_pointer_array_get_count(
-                               &trace_chunk->top_level_directories);
+                                         &trace_chunk->top_level_directories);
 
                ret = lttng_directory_handle_create_subdirectory_as_user(
-                               &trace_chunk->session_output_directory.value,
+                               trace_chunk->session_output_directory,
                                DEFAULT_TEMPORARY_CHUNK_RENAME_DIRECTORY,
                                DIR_CREATION_MODE,
                                !trace_chunk->credentials.value.use_current_user ?
@@ -855,10 +1049,10 @@ void lttng_trace_chunk_move_to_completed(struct lttng_trace_chunk *trace_chunk)
                                        DEFAULT_TEMPORARY_CHUNK_RENAME_DIRECTORY);
                }
 
-               ret = lttng_directory_handle_init_from_handle(&temporary_rename_directory,
+               temporary_rename_directory = lttng_directory_handle_create_from_handle(
                                DEFAULT_TEMPORARY_CHUNK_RENAME_DIRECTORY,
-                               &trace_chunk->session_output_directory.value);
-               if (ret) {
+                               trace_chunk->session_output_directory);
+               if (!temporary_rename_directory) {
                        ERR("Failed to get handle to temporary trace chunk rename directory");
                        goto end;
                }
@@ -869,9 +1063,9 @@ void lttng_trace_chunk_move_to_completed(struct lttng_trace_chunk *trace_chunk)
                                                &trace_chunk->top_level_directories, i);
 
                        ret = lttng_directory_handle_rename_as_user(
-                                       &trace_chunk->session_output_directory.value,
+                                       trace_chunk->session_output_directory,
                                        top_level_name,
-                                       &temporary_rename_directory,
+                                       temporary_rename_directory,
                                        top_level_name,
                                        LTTNG_OPTIONAL_GET(trace_chunk->credentials).use_current_user ?
                                                NULL :
@@ -879,12 +1073,12 @@ void lttng_trace_chunk_move_to_completed(struct lttng_trace_chunk *trace_chunk)
                        if (ret) {
                                PERROR("Failed to move \"%s\" to temporary trace chunk rename directory",
                                                top_level_name);
-                               lttng_directory_handle_fini(
-                                               &temporary_rename_directory);
+                               lttng_directory_handle_put(
+                                               temporary_rename_directory);
                                goto end;
                        }
                }
-               lttng_directory_handle_fini(&temporary_rename_directory);
+               lttng_directory_handle_put(temporary_rename_directory);
                directory_to_rename = DEFAULT_TEMPORARY_CHUNK_RENAME_DIRECTORY;
                free_directory_to_rename = false;
        } else {
@@ -892,6 +1086,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;
        }
@@ -904,7 +1099,7 @@ void lttng_trace_chunk_move_to_completed(struct lttng_trace_chunk *trace_chunk)
        }
 
        ret = lttng_directory_handle_create_subdirectory_as_user(
-                       &trace_chunk->session_output_directory.value,
+                       trace_chunk->session_output_directory,
                        DEFAULT_ARCHIVED_TRACE_CHUNKS_DIRECTORY,
                        DIR_CREATION_MODE,
                        !trace_chunk->credentials.value.use_current_user ?
@@ -916,20 +1111,18 @@ void lttng_trace_chunk_move_to_completed(struct lttng_trace_chunk *trace_chunk)
                goto end;
        }
 
-       ret = lttng_directory_handle_init_from_handle(
-                       &archived_chunks_directory.value,
+       archived_chunks_directory = lttng_directory_handle_create_from_handle(
                        DEFAULT_ARCHIVED_TRACE_CHUNKS_DIRECTORY,
-                       &trace_chunk->session_output_directory.value);
-       if (ret) {
+                       trace_chunk->session_output_directory);
+       if (!archived_chunks_directory) {
                PERROR("Failed to get handle to archived trace chunks directory");
                goto end;
        }
-       archived_chunks_directory.is_set = true;
 
        ret = lttng_directory_handle_rename_as_user(
-                       &trace_chunk->session_output_directory.value,
+                       trace_chunk->session_output_directory,
                        directory_to_rename,
-                       &archived_chunks_directory.value,
+                       archived_chunks_directory,
                        archived_chunk_name,
                        LTTNG_OPTIONAL_GET(trace_chunk->credentials).use_current_user ?
                                NULL :
@@ -940,15 +1133,31 @@ void lttng_trace_chunk_move_to_completed(struct lttng_trace_chunk *trace_chunk)
        }
 
 end:
-       if (archived_chunks_directory.is_set) {
-               lttng_directory_handle_fini(&archived_chunks_directory.value);
-       }
+       lttng_directory_handle_put(archived_chunks_directory);
        free(archived_chunk_name);
        if (free_directory_to_rename) {
                free(directory_to_rename);
        }
 }
 
+LTTNG_HIDDEN
+enum lttng_trace_chunk_status lttng_trace_chunk_get_close_command(
+               struct lttng_trace_chunk *chunk,
+               enum lttng_trace_chunk_command_type *command_type)
+{
+       enum lttng_trace_chunk_status status = LTTNG_TRACE_CHUNK_STATUS_OK;
+
+       pthread_mutex_lock(&chunk->lock);
+       if (chunk->close_command.is_set) {
+               *command_type = chunk->close_command.value;
+               status = LTTNG_TRACE_CHUNK_STATUS_OK;
+       } else {
+               status = LTTNG_TRACE_CHUNK_STATUS_NONE;
+       }
+       pthread_mutex_unlock(&chunk->lock);
+       return status;
+}
+
 LTTNG_HIDDEN
 enum lttng_trace_chunk_status lttng_trace_chunk_set_close_command(
                struct lttng_trace_chunk *chunk,
@@ -959,7 +1168,7 @@ enum lttng_trace_chunk_status lttng_trace_chunk_set_close_command(
        if (close_command < LTTNG_TRACE_CHUNK_COMMAND_TYPE_MOVE_TO_COMPLETED ||
                        close_command >= LTTNG_TRACE_CHUNK_COMMAND_TYPE_MAX) {
                status = LTTNG_TRACE_CHUNK_STATUS_INVALID_ARGUMENT;
-               goto end_unlock;
+               goto end;
        }
 
        pthread_mutex_lock(&chunk->lock);
@@ -971,12 +1180,36 @@ enum lttng_trace_chunk_status lttng_trace_chunk_set_close_command(
                DBG("Setting trace chunk close command to \"%s\"",
                                close_command_names[close_command]);
         }
-       LTTNG_OPTIONAL_SET(&chunk->close_command, close_command);
+       /*
+        * Unset close command for no-op for backward compatibility with relayd
+        * 2.11.
+        */
+       if (close_command != LTTNG_TRACE_CHUNK_COMMAND_TYPE_NO_OPERATION) {
+               LTTNG_OPTIONAL_SET(&chunk->close_command, close_command);
+       } else {
+               LTTNG_OPTIONAL_UNSET(&chunk->close_command);
+       }
        pthread_mutex_unlock(&chunk->lock);
-end_unlock:
+end:
        return status;
 }
 
+LTTNG_HIDDEN
+const char *lttng_trace_chunk_command_type_get_name(
+               enum lttng_trace_chunk_command_type command)
+{
+       switch (command) {
+       case LTTNG_TRACE_CHUNK_COMMAND_TYPE_MOVE_TO_COMPLETED:
+               return "move to completed trace chunk folder";
+       case LTTNG_TRACE_CHUNK_COMMAND_TYPE_NO_OPERATION:
+               return "no operation";
+       case LTTNG_TRACE_CHUNK_COMMAND_TYPE_DELETE:
+               return "delete";
+       default:
+               abort();
+       }
+}
+
 LTTNG_HIDDEN
 bool lttng_trace_chunk_get(struct lttng_trace_chunk *chunk)
 {
@@ -1055,7 +1288,7 @@ end:
        return registry;
 error:
        lttng_trace_chunk_registry_destroy(registry);
-       goto end;
+       return NULL;
 }
 
 LTTNG_HIDDEN
@@ -1088,15 +1321,16 @@ lttng_trace_chunk_registry_element_create_from_chunk(
 
        element->chunk = *chunk;
        lttng_trace_chunk_init(&element->chunk);
-       if (chunk->session_output_directory.is_set) {
-               element->chunk.session_output_directory.value =
-                               lttng_directory_handle_move(
-                                       &chunk->session_output_directory.value);
+       if (chunk->session_output_directory) {
+               /* Transferred ownership. */
+               element->chunk.session_output_directory =
+                               chunk->session_output_directory;
+               chunk->session_output_directory = NULL;
        }
-       if (chunk->chunk_directory.is_set) {
-               element->chunk.chunk_directory.value =
-                               lttng_directory_handle_move(
-                                       &chunk->chunk_directory.value);
+       if (chunk->chunk_directory) {
+               /* Transferred ownership. */
+               element->chunk.chunk_directory = chunk->chunk_directory;
+               chunk->chunk_directory = NULL;
        }
        /*
         * The original chunk becomes invalid; the name attribute is transferred
@@ -1155,7 +1389,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;
                        }
                }
@@ -1245,6 +1479,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(
@@ -1254,3 +1523,49 @@ lttng_trace_chunk_registry_find_anonymous_chunk(
         return _lttng_trace_chunk_registry_find_chunk(registry,
                        session_id, NULL);
 }
+
+unsigned int lttng_trace_chunk_registry_put_each_chunk(
+               struct lttng_trace_chunk_registry *registry)
+{
+       struct cds_lfht_iter iter;
+       struct lttng_trace_chunk_registry_element *chunk_element;
+       unsigned int trace_chunks_left = 0;
+
+       DBG("Releasing trace chunk registry to all trace chunks");
+       rcu_read_lock();
+       cds_lfht_for_each_entry(registry->ht,
+                       &iter, chunk_element, trace_chunk_registry_ht_node) {
+               const char *chunk_id_str = "none";
+               char chunk_id_buf[MAX_INT_DEC_LEN(uint64_t)];
+
+               pthread_mutex_lock(&chunk_element->chunk.lock);
+               if (chunk_element->chunk.id.is_set) {
+                       int fmt_ret;
+
+                       fmt_ret = snprintf(chunk_id_buf, sizeof(chunk_id_buf),
+                                       "%" PRIu64,
+                                       chunk_element->chunk.id.value);
+                       if (fmt_ret < 0 || fmt_ret >= sizeof(chunk_id_buf)) {
+                               chunk_id_str = "formatting error";
+                       } else {
+                               chunk_id_str = chunk_id_buf;
+                       }
+               }
+
+               DBG("Releasing reference to trace chunk: session_id = %" PRIu64
+                               "chunk_id = %s, name = \"%s\", status = %s",
+                               chunk_element->session_id,
+                               chunk_id_str,
+                               chunk_element->chunk.name ? : "none",
+                               chunk_element->chunk.close_command.is_set ?
+                                               "open" : "closed");
+               pthread_mutex_unlock(&chunk_element->chunk.lock);
+               lttng_trace_chunk_put(&chunk_element->chunk);
+               trace_chunks_left++;
+       }
+       rcu_read_unlock();
+       DBG("Released reference to %u trace chunks in %s()", trace_chunks_left,
+                       __FUNCTION__);
+
+       return trace_chunks_left;
+}
This page took 0.035083 seconds and 5 git commands to generate.