trace-chunk: Introduce chunk "path", relayd session "ongoing_rotation", sessiond...
authorMathieu Desnoyers <mathieu.desnoyers@efficios.com>
Thu, 12 Dec 2019 17:22:14 +0000 (12:22 -0500)
committerJérémie Galarneau <jeremie.galarneau@efficios.com>
Thu, 19 Dec 2019 23:33:02 +0000 (18:33 -0500)
This commit introduces new attributes in 3 different structures because
those are used in surrounding areas of the code.

Introduce a trace chunk path attribute which tracks where the chunk
currently keeps its files.

It allows updating the current chunk location with the "rename"
API without having to rely on changing the chunk name override,
which is an attribute we may want to keep using when we archive
the chunk.

Separating the "path" from the "name override" attribute allows
easy manipulation of the chunk output without having to keep the
name override around in the caller code.

Introduce an "ongoing_rotation" relayd session attribute to allow
live viewers to retry while a rotation is ongoing. This ongoing
rotation attribute is introduced in the same commit as the path
chunk attribute because they are used in a surrounding area of the code.

Introduce a "rotated" sessiond session attribute in this commit
because it is used in a surrounding area of the code. This rotated
attribute tracks whether an explicit rotation has been performed
on the session. It is a preparation step for the clear feature,
which will use this to figure out whether it needs to clear the
"root" output path (no rotation prior to clear") or if it needs
to clear to a new path. Before introduction of the clear feature,
a chunk_id of 0 was used to identify this, but because clear will
increment the chunk id without changing the path, we need to track
this explicitly through the "rotated" session flag.

Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Change-Id: Ifdecc66cb4849f3e5f7476ab7db48d8f7532a6d3
Signed-off-by: Jérémie Galarneau <jeremie.galarneau@efficios.com>
src/bin/lttng-relayd/main.c
src/bin/lttng-relayd/session.h
src/bin/lttng-sessiond/cmd.c
src/bin/lttng-sessiond/session.c
src/bin/lttng-sessiond/session.h
src/common/consumer/consumer.c
src/common/defaults.h
src/common/trace-chunk.c
src/common/trace-chunk.h

index d874a9c50bdcabfbbc5bf0bc49c584e1eb635665..749feb6f6f319a95c86d62a68af0b5f693a7c4d3 100644 (file)
@@ -2459,6 +2459,7 @@ static int relay_create_trace_chunk(const struct lttcomm_relayd_hdr *recv_hdr,
        enum lttng_error_code reply_code = LTTNG_OK;
        enum lttng_trace_chunk_status chunk_status;
        struct lttng_directory_handle *session_output = NULL;
+       const char *new_path;
 
        if (!session || !conn->version_check_done) {
                ERR("Trying to create a trace chunk before version check");
@@ -2485,8 +2486,29 @@ static int relay_create_trace_chunk(const struct lttcomm_relayd_hdr *recv_hdr,
        msg->creation_timestamp = be64toh(msg->creation_timestamp);
        msg->override_name_length = be32toh(msg->override_name_length);
 
+       if (session->current_trace_chunk &&
+                       !lttng_trace_chunk_get_name_overridden(session->current_trace_chunk)) {
+               chunk_status = lttng_trace_chunk_rename_path(session->current_trace_chunk,
+                                       DEFAULT_CHUNK_TMP_OLD_DIRECTORY);
+               if (chunk_status != LTTNG_TRACE_CHUNK_STATUS_OK) {
+                       ERR("Failed to rename old chunk");
+                       ret = -1;
+                       reply_code = LTTNG_ERR_UNK;
+                       goto end;
+               }
+       }
+       session->ongoing_rotation = true;
+       if (!session->current_trace_chunk) {
+               if (!session->has_rotated) {
+                       new_path = "";
+               } else {
+                       new_path = NULL;
+               }
+       } else {
+               new_path = DEFAULT_CHUNK_TMP_NEW_DIRECTORY;
+       }
        chunk = lttng_trace_chunk_create(
-                       msg->chunk_id, msg->creation_timestamp);
+                       msg->chunk_id, msg->creation_timestamp, new_path);
        if (!chunk) {
                ERR("Failed to create trace chunk in trace chunk creation command");
                ret = -1;
@@ -2581,6 +2603,9 @@ static int relay_create_trace_chunk(const struct lttcomm_relayd_hdr *recv_hdr,
                        conn->session->current_trace_chunk;
        conn->session->current_trace_chunk = published_chunk;
        published_chunk = NULL;
+       if (!conn->session->pending_closure_trace_chunk) {
+               session->ongoing_rotation = false;
+       }
 end_unlock_session:
        pthread_mutex_unlock(&conn->session->lock);
 end:
@@ -2624,6 +2649,7 @@ static int relay_close_trace_chunk(const struct lttcomm_relayd_hdr *recv_hdr,
        size_t path_length = 0;
        const char *chunk_name = NULL;
        struct lttng_dynamic_buffer reply_payload;
+       const char *new_path;
 
        lttng_dynamic_buffer_init(&reply_payload);
 
@@ -2683,6 +2709,43 @@ static int relay_close_trace_chunk(const struct lttcomm_relayd_hdr *recv_hdr,
                goto end_unlock_session;
        }
 
+       if (session->current_trace_chunk && session->current_trace_chunk != chunk &&
+                       !lttng_trace_chunk_get_name_overridden(session->current_trace_chunk)) {
+               if (close_command.is_set &&
+                               close_command.value == LTTNG_TRACE_CHUNK_COMMAND_TYPE_DELETE &&
+                               !session->has_rotated) {
+                       /* New chunk stays in session output directory. */
+                       new_path = "";
+               } else {
+                       /* Use chunk name for new chunk. */
+                       new_path = NULL;
+               }
+               /* Rename new chunk path. */
+               chunk_status = lttng_trace_chunk_rename_path(session->current_trace_chunk,
+                               new_path);
+               if (chunk_status != LTTNG_TRACE_CHUNK_STATUS_OK) {
+                       ret = -1;
+                       goto end;
+               }
+               session->ongoing_rotation = false;
+       }
+       if ((!close_command.is_set ||
+                       close_command.value == LTTNG_TRACE_CHUNK_COMMAND_TYPE_NO_OPERATION) &&
+                       !lttng_trace_chunk_get_name_overridden(chunk)) {
+               const char *old_path;
+
+               if (!session->has_rotated) {
+                       old_path = "";
+               } else {
+                       old_path = NULL;
+               }
+               /* We need to move back the .tmp_old_chunk to its rightful place. */
+               chunk_status = lttng_trace_chunk_rename_path(chunk, old_path);
+               if (chunk_status != LTTNG_TRACE_CHUNK_STATUS_OK) {
+                       ret = -1;
+                       goto end;
+               }
+       }
        chunk_status = lttng_trace_chunk_set_close_timestamp(
                        chunk, close_timestamp);
        if (chunk_status != LTTNG_TRACE_CHUNK_STATUS_OK) {
index aa2a58a98f677351f33f2c9f3523495bf61568da..43f76a4aad54eadc7ac3e53f311bab00a748653b 100644 (file)
@@ -134,6 +134,11 @@ struct relay_session {
        struct cds_list_head viewer_session_node;
        struct lttng_trace_chunk *current_trace_chunk;
        struct lttng_trace_chunk *pending_closure_trace_chunk;
+       /*
+        * Prevent live viewers from taking of copy of the chunk
+        * while new chunk has a temporary directory name.
+        */
+       bool ongoing_rotation;
        struct rcu_head rcu_node;       /* For call_rcu teardown. */
 };
 
index 6f824bf316811c2fa486cb4a661abcca5c5b4c3f..db07082dbc4e0e50620d4b38d9bf27c97ac8b787 100644 (file)
@@ -3328,9 +3328,7 @@ int cmd_destroy_session(struct ltt_session *session,
                session->rotate_size = 0;
        }
 
-       if (session->most_recent_chunk_id.is_set &&
-                       session->most_recent_chunk_id.value != 0 &&
-                       session->current_trace_chunk && session->output_traces) {
+       if (session->rotated && session->current_trace_chunk && session->output_traces) {
                /*
                 * Perform a last rotation on destruction if rotations have
                 * occurred during the session's lifetime.
index 0da2058fdf28dbbef05f0d2490cfbf49a089a294..88bbe1309c4a1270cbbf418a97af3d5aeee57fb5 100644 (file)
@@ -589,6 +589,7 @@ struct lttng_trace_chunk *session_create_new_trace_chunk(
        };
        uint64_t next_chunk_id;
        const struct consumer_output *output;
+       const char *new_path;
 
        if (consumer_output_override) {
                output = consumer_output_override;
@@ -612,8 +613,26 @@ struct lttng_trace_chunk *session_create_new_trace_chunk(
        next_chunk_id = session->most_recent_chunk_id.is_set ?
                        session->most_recent_chunk_id.value + 1 : 0;
 
+       if (session->current_trace_chunk &&
+                       !lttng_trace_chunk_get_name_overridden(session->current_trace_chunk)) {
+               chunk_status = lttng_trace_chunk_rename_path(session->current_trace_chunk,
+                                       DEFAULT_CHUNK_TMP_OLD_DIRECTORY);
+               if (chunk_status != LTTNG_TRACE_CHUNK_STATUS_OK) {
+                       goto error;
+               }
+       }
+       if (!session->current_trace_chunk) {
+               if (!session->rotated) {
+                       new_path = "";
+               } else {
+                       new_path = NULL;
+               }
+       } else {
+               new_path = DEFAULT_CHUNK_TMP_NEW_DIRECTORY;
+       }
+
        trace_chunk = lttng_trace_chunk_create(next_chunk_id,
-                       chunk_creation_ts);
+                       chunk_creation_ts, new_path);
        if (!trace_chunk) {
                goto error;
        }
@@ -678,6 +697,7 @@ int session_close_trace_chunk(struct ltt_session *session,
        struct consumer_socket *socket;
        enum lttng_trace_chunk_status chunk_status;
        const time_t chunk_close_timestamp = time(NULL);
+       const char *new_path;
 
        chunk_status = lttng_trace_chunk_set_close_command(
                        trace_chunk, close_command);
@@ -692,6 +712,44 @@ int session_close_trace_chunk(struct ltt_session *session,
                ret = -1;
                goto end;
        }
+
+       if (close_command == LTTNG_TRACE_CHUNK_COMMAND_TYPE_DELETE && !session->rotated) {
+               /* New chunk stays in session output directory. */
+               new_path = "";
+       } else {
+               /* Use chunk name for new chunk. */
+               new_path = NULL;
+       }
+       if (session->current_trace_chunk &&
+                       !lttng_trace_chunk_get_name_overridden(session->current_trace_chunk)) {
+               /* Rename new chunk path. */
+               chunk_status = lttng_trace_chunk_rename_path(session->current_trace_chunk,
+                                       new_path);
+               if (chunk_status != LTTNG_TRACE_CHUNK_STATUS_OK) {
+                       ret = -1;
+                       goto end;
+               }
+       }
+       if (!lttng_trace_chunk_get_name_overridden(trace_chunk) &&
+                       close_command == LTTNG_TRACE_CHUNK_COMMAND_TYPE_NO_OPERATION) {
+               const char *old_path;
+
+               if (!session->rotated) {
+                       old_path = "";
+               } else {
+                       old_path = NULL;
+               }
+               /* We need to move back the .tmp_old_chunk to its rightful place. */
+               chunk_status = lttng_trace_chunk_rename_path(trace_chunk,
+                                       old_path);
+               if (chunk_status != LTTNG_TRACE_CHUNK_STATUS_OK) {
+                       ret = -1;
+                       goto end;
+               }
+       }
+       if (close_command == LTTNG_TRACE_CHUNK_COMMAND_TYPE_MOVE_TO_COMPLETED) {
+               session->rotated = true;
+       }
        chunk_status = lttng_trace_chunk_set_close_timestamp(trace_chunk,
                        chunk_close_timestamp);
        if (chunk_status != LTTNG_TRACE_CHUNK_STATUS_OK) {
index da3805658cd28e1255292d6250ae6882f779a6d0..606c42269b4f9b4d4576536c8b113d2493d5fa1e 100644 (file)
@@ -181,6 +181,10 @@ struct ltt_session {
         * subsequent rotate (without prior start) will return an error.
         */
        bool cleared_after_last_stop;
+       /*
+        * True if the session has had an explicit non-quiet rotation.
+        */
+       bool rotated;
        /*
         * Condition and trigger for size-based rotations.
         */
index 26209279ee65a49ec8c06ba88baed8dd275da90e..0263489ddd8a908bacd2096ec14e68cfafbb1bd7 100644 (file)
@@ -4603,7 +4603,7 @@ enum lttcomm_return_code lttng_consumer_create_trace_chunk(
         * and LTTNG_CONSUMER_DESTROY_TRACE_CHUNK commands.
         */
        created_chunk = lttng_trace_chunk_create(chunk_id,
-                       chunk_creation_timestamp);
+                       chunk_creation_timestamp, NULL);
        if (!created_chunk) {
                ERR("Failed to create trace chunk");
                ret_code = LTTCOMM_CONSUMERD_CREATE_TRACE_CHUNK_FAILED;
index 155739f460a2d0615f0c4053ae7954afa4d97351..2c3e80f436d586f067339dad88f9b5c02f2db202 100644 (file)
  * Name of the intermediate directory used to rename the trace chunk of a
  * session's first rotation.
  */
-#define DEFAULT_TEMPORARY_CHUNK_RENAME_DIRECTORY       ".tmp_rename_chunk"
+#define DEFAULT_CHUNK_TMP_OLD_DIRECTORY                        ".tmp_old_chunk"
+#define DEFAULT_CHUNK_TMP_NEW_DIRECTORY                        ".tmp_new_chunk"
 #define DEFAULT_ARCHIVED_TRACE_CHUNKS_DIRECTORY                "archives"
 
 /*
index c549f46b33c855334814355ef8a6e37f6cacadf2..266a02ee68e3933ea2533c70572c714098c4df45 100644 (file)
@@ -55,18 +55,26 @@ enum trace_chunk_mode {
  * since only one thread may access a chunk during its destruction (the last
  * to release its reference to the chunk).
  */
-typedef void (*chunk_close_command)(struct lttng_trace_chunk *trace_chunk);
+typedef int (*chunk_command)(struct lttng_trace_chunk *trace_chunk);
 
 /* Move a completed trace chunk to the 'completed' trace archive folder. */
 static
-void lttng_trace_chunk_move_to_completed(struct lttng_trace_chunk *trace_chunk);
+int lttng_trace_chunk_move_to_completed_post_release(struct lttng_trace_chunk *trace_chunk);
+static
+enum lttng_trace_chunk_status lttng_trace_chunk_rename_path_no_lock(
+               struct lttng_trace_chunk *chunk, const char *path);
 
 struct chunk_credentials {
        bool use_current_user;
        struct lttng_credentials user;
 };
 
-/* NOTE: Make sure to update lttng_trace_chunk_copy if you modify this. */
+/*
+ * NOTE: Make sure to update:
+ * - lttng_trace_chunk_copy(),
+ * - lttng_trace_chunk_registry_element_create_from_chunk()
+ * if you modify this structure.
+ */
 struct lttng_trace_chunk {
        pthread_mutex_t lock;
        struct urcu_ref ref;
@@ -87,6 +95,7 @@ struct lttng_trace_chunk {
        bool in_registry_element;
        bool name_overridden;
        char *name;
+       char *path;
        /* An unset id means the chunk is anonymous. */
        LTTNG_OPTIONAL(uint64_t) id;
        LTTNG_OPTIONAL(time_t) timestamp_creation;
@@ -123,9 +132,9 @@ char *close_command_names[] = {
 };
 
 static const
-chunk_close_command close_command_funcs[] = {
+chunk_command close_command_post_release_funcs[] = {
        [LTTNG_TRACE_CHUNK_COMMAND_TYPE_MOVE_TO_COMPLETED] =
-                       lttng_trace_chunk_move_to_completed,
+                       lttng_trace_chunk_move_to_completed_post_release,
 };
 
 static
@@ -242,6 +251,8 @@ void lttng_trace_chunk_fini(struct lttng_trace_chunk *chunk)
        }
        free(chunk->name);
        chunk->name = NULL;
+       free(chunk->path);
+       chunk->path = NULL;
        lttng_dynamic_pointer_array_reset(&chunk->top_level_directories);
        lttng_dynamic_pointer_array_reset(&chunk->files);
        pthread_mutex_destroy(&chunk->lock);
@@ -271,7 +282,7 @@ struct lttng_trace_chunk *lttng_trace_chunk_create_anonymous(void)
 
 LTTNG_HIDDEN
 struct lttng_trace_chunk *lttng_trace_chunk_create(
-               uint64_t chunk_id, time_t chunk_creation_time)
+               uint64_t chunk_id, time_t chunk_creation_time, const char *path)
 {
        struct lttng_trace_chunk *chunk;
         char chunk_creation_datetime_buf[16] = {};
@@ -309,6 +320,19 @@ struct lttng_trace_chunk *lttng_trace_chunk_create(
                        goto error;
                }
         }
+       if (path) {
+               chunk->path = strdup(path);
+               if (!chunk->path) {
+                       goto error;
+               }
+       } else {
+               if (chunk->name) {
+                       chunk->path = strdup(chunk->name);
+                       if (!chunk->path) {
+                               goto error;
+                       }
+               }
+       }
 
         DBG("Chunk name set to \"%s\"", chunk->name ? : "(none)");
 end:
@@ -352,6 +376,13 @@ struct lttng_trace_chunk *lttng_trace_chunk_copy(
                        goto error_unlock;
                }
        }
+       if (source_chunk->path) {
+               new_chunk->path = strdup(source_chunk->path);
+               if (!new_chunk->path) {
+                       ERR("Failed to copy source trace chunk path in %s()",
+                                       __FUNCTION__);
+               }
+       }
        new_chunk->id = source_chunk->id;
        new_chunk->timestamp_creation = source_chunk->timestamp_creation;
        new_chunk->timestamp_close = source_chunk->timestamp_close;
@@ -520,9 +551,10 @@ enum lttng_trace_chunk_status lttng_trace_chunk_override_name(
                struct lttng_trace_chunk *chunk, const char *name)
 
 {
-       char *new_name;
        enum lttng_trace_chunk_status status = LTTNG_TRACE_CHUNK_STATUS_OK;
+       char *new_name, *new_path;
 
+       DBG("Override trace chunk name from %s to %s", chunk->name, name);
        if (!is_valid_chunk_name(name)) {
                ERR("Attempted to set an invalid name on a trace chunk: name = %s",
                                name ? : "NULL");
@@ -537,6 +569,7 @@ enum lttng_trace_chunk_status lttng_trace_chunk_override_name(
                status = LTTNG_TRACE_CHUNK_STATUS_INVALID_OPERATION;
                goto end_unlock;
        }
+
        new_name = strdup(name);
        if (!new_name) {
                ERR("Failed to allocate new trace chunk name");
@@ -545,13 +578,239 @@ enum lttng_trace_chunk_status lttng_trace_chunk_override_name(
        }
        free(chunk->name);
        chunk->name = new_name;
+
+       new_path = strdup(name);
+       if (!new_path) {
+               ERR("Failed to allocate new trace chunk path");
+               status = LTTNG_TRACE_CHUNK_STATUS_ERROR;
+               goto end_unlock;
+       }
+       free(chunk->path);
+       chunk->path = new_path;
+
        chunk->name_overridden = true;
-end_unlock:    
+end_unlock:
        pthread_mutex_unlock(&chunk->lock);
 end:
        return status;
 }
 
+static
+enum lttng_trace_chunk_status lttng_trace_chunk_rename_path_no_lock(
+               struct lttng_trace_chunk *chunk, const char *path)
+
+{
+       enum lttng_trace_chunk_status status = LTTNG_TRACE_CHUNK_STATUS_OK;
+       struct lttng_directory_handle *rename_directory = NULL;
+       char *new_path, *old_path;
+       int ret;
+
+       if (chunk->name_overridden) {
+               status = LTTNG_TRACE_CHUNK_STATUS_ERROR;
+               goto end;
+       }
+
+       old_path = chunk->path;
+       DBG("lttng_trace_chunk_rename_path from %s to %s", old_path, path);
+
+       if ((!old_path && !path) ||
+                       (old_path && path && !strcmp(old_path, path)))  {
+               goto end;
+       }
+       /*
+        * Use chunk name as path if NULL path is specified.
+        */
+       if (!path) {
+               path = chunk->name;
+       }
+
+       /* Renaming from "" to "" is not accepted. */
+       if (path[0] == '\0' && old_path[0] == '\0') {
+               status = LTTNG_TRACE_CHUNK_STATUS_ERROR;
+               goto end;
+       }
+
+       /*
+        * If a rename is performed on a chunk for which the chunk_directory
+        * is not set (yet), or the session_output_directory is not set
+        * (interacting with a relay daemon), there is no rename to perform.
+        */
+       if (!chunk->chunk_directory ||
+                       !chunk->session_output_directory) {
+               goto skip_move;
+       }
+
+       if (old_path[0] != '\0' && path[0] != '\0') {
+               /* Rename chunk directory. */
+               ret = lttng_directory_handle_rename_as_user(
+                       chunk->session_output_directory,
+                       old_path,
+                       chunk->session_output_directory,
+                       path,
+                       LTTNG_OPTIONAL_GET(chunk->credentials).use_current_user ?
+                               NULL :
+                               &chunk->credentials.value.user);
+               if (ret) {
+                       PERROR("Failed to move trace chunk directory \"%s\" to \"%s\"",
+                                       old_path, path);
+                       status = LTTNG_TRACE_CHUNK_STATUS_ERROR;
+                       goto end;
+               }
+               rename_directory = lttng_directory_handle_create_from_handle(
+                               path,
+                               chunk->session_output_directory);
+               if (!rename_directory) {
+                       ERR("Failed to get handle to trace chunk rename directory");
+                       status = LTTNG_TRACE_CHUNK_STATUS_ERROR;
+                       goto end;
+               }
+
+               /* Release old handle. */
+               lttng_directory_handle_put(chunk->chunk_directory);
+               /*
+                * Transfer new handle reference to chunk as the current chunk
+                * handle.
+                */
+               chunk->chunk_directory = rename_directory;
+               rename_directory = NULL;
+       } else if (old_path[0] == '\0') {
+               size_t i, count = lttng_dynamic_pointer_array_get_count(
+                               &chunk->top_level_directories);
+
+               ret = lttng_directory_handle_create_subdirectory_as_user(
+                               chunk->session_output_directory,
+                               path,
+                               DIR_CREATION_MODE,
+                               LTTNG_OPTIONAL_GET(chunk->credentials).use_current_user ?
+                                       NULL :
+                                       &chunk->credentials.value.user);
+               if (ret) {
+                       PERROR("Failed to create trace chunk rename directory \"%s\"",
+                                       path);
+                       status = LTTNG_TRACE_CHUNK_STATUS_ERROR;
+                       goto end;
+               }
+
+               rename_directory = lttng_directory_handle_create_from_handle(
+                               path, chunk->session_output_directory);
+               if (!rename_directory) {
+                       ERR("Failed to get handle to trace chunk rename directory");
+                       status = LTTNG_TRACE_CHUNK_STATUS_ERROR;
+                       goto end;
+               }
+
+               /* Move toplevel directories. */
+               for (i = 0; i < count; i++) {
+                       const char *top_level_name =
+                               lttng_dynamic_pointer_array_get_pointer(
+                                       &chunk->top_level_directories, i);
+
+                       ret = lttng_directory_handle_rename_as_user(
+                                       chunk->chunk_directory,
+                                       top_level_name,
+                                       rename_directory,
+                                       top_level_name,
+                                       LTTNG_OPTIONAL_GET(chunk->credentials).use_current_user ?
+                                               NULL :
+                                               &chunk->credentials.value.user);
+                       if (ret) {
+                               PERROR("Failed to move \"%s\" to trace chunk rename directory",
+                                               top_level_name);
+                               status = LTTNG_TRACE_CHUNK_STATUS_ERROR;
+                               goto end;
+                       }
+               }
+               /* Release old handle. */
+               lttng_directory_handle_put(chunk->chunk_directory);
+               /*
+                * Transfer new handle reference to chunk as the current chunk
+                * handle.
+                */
+               chunk->chunk_directory = rename_directory;
+               rename_directory = NULL;
+       } else {
+               size_t i, count = lttng_dynamic_pointer_array_get_count(
+                               &chunk->top_level_directories);
+               const bool reference_acquired = lttng_directory_handle_get(
+                               chunk->session_output_directory);
+
+               assert(reference_acquired);
+               rename_directory = chunk->session_output_directory;
+
+               /* Move toplevel directories. */
+               for (i = 0; i < count; i++) {
+                       const char *top_level_name =
+                               lttng_dynamic_pointer_array_get_pointer(
+                                       &chunk->top_level_directories, i);
+
+                       ret = lttng_directory_handle_rename_as_user(
+                                       chunk->chunk_directory,
+                                       top_level_name,
+                                       rename_directory,
+                                       top_level_name,
+                                       LTTNG_OPTIONAL_GET(chunk->credentials).use_current_user ?
+                                               NULL :
+                                               &chunk->credentials.value.user);
+                       if (ret) {
+                               PERROR("Failed to move \"%s\" to trace chunk rename directory",
+                                               top_level_name);
+                               status = LTTNG_TRACE_CHUNK_STATUS_ERROR;
+                               goto end;
+                       }
+               }
+               /* Release old handle. */
+               lttng_directory_handle_put(chunk->chunk_directory);
+               /*
+                * Transfer new handle reference to chunk as the current chunk
+                * handle.
+                */
+               chunk->chunk_directory = rename_directory;
+               rename_directory = NULL;
+
+               /* Remove old directory. */
+               status = lttng_directory_handle_remove_subdirectory(
+                               chunk->session_output_directory,
+                               old_path);
+               if (status != LTTNG_TRACE_CHUNK_STATUS_OK) {
+                       ERR("Error removing subdirectory '%s' file when deleting chunk",
+                               old_path);
+                       ret = -1;
+                       goto end;
+               }
+       }
+
+skip_move:
+       if (path) {
+               new_path = strdup(path);
+               if (!new_path) {
+                       ERR("Failed to allocate new trace chunk path");
+                       status = LTTNG_TRACE_CHUNK_STATUS_ERROR;
+                       goto end;
+               }
+       } else {
+               new_path = NULL;
+       }
+       free(chunk->path);
+       chunk->path = new_path;
+end:
+       lttng_directory_handle_put(rename_directory);
+       return status;
+}
+
+LTTNG_HIDDEN
+enum lttng_trace_chunk_status lttng_trace_chunk_rename_path(
+               struct lttng_trace_chunk *chunk, const char *path)
+
+{
+       enum lttng_trace_chunk_status status;
+
+       pthread_mutex_lock(&chunk->lock);
+       status = lttng_trace_chunk_rename_path_no_lock(chunk, path);
+       pthread_mutex_unlock(&chunk->lock);
+
+       return status;
+}
+
 LTTNG_HIDDEN
 enum lttng_trace_chunk_status lttng_trace_chunk_get_credentials(
                struct lttng_trace_chunk *chunk,
@@ -641,32 +900,39 @@ enum lttng_trace_chunk_status lttng_trace_chunk_set_as_owner(
                status = LTTNG_TRACE_CHUNK_STATUS_ERROR;
                goto end;
        }
-
-       if (chunk->name) {
-               /*
-                * A nameless chunk does not need its own output directory.
-                * The session's output directory will be used.
-                */
+       if (chunk->path[0] != '\0') {
                ret = lttng_directory_handle_create_subdirectory_as_user(
                                session_output_directory,
-                               chunk->name,
+                               chunk->path,
                                DIR_CREATION_MODE,
                                !chunk->credentials.value.use_current_user ?
                                        &chunk->credentials.value.user : NULL);
                if (ret) {
                        PERROR("Failed to create chunk output directory \"%s\"",
-                               chunk->name);
+                               chunk->path);
                        status = LTTNG_TRACE_CHUNK_STATUS_ERROR;
                        goto end;
                }
-       }
-       chunk_directory_handle = lttng_directory_handle_create_from_handle(
-                       chunk->name,
-                       session_output_directory);
-       if (!chunk_directory_handle) {
-               /* The function already logs on all error paths. */
-               status = LTTNG_TRACE_CHUNK_STATUS_ERROR;
-               goto end;
+               chunk_directory_handle =
+                               lttng_directory_handle_create_from_handle(
+                                       chunk->path,
+                                       session_output_directory);
+               if (!chunk_directory_handle) {
+                       /* The function already logs on all error paths. */
+                       status = LTTNG_TRACE_CHUNK_STATUS_ERROR;
+                       goto end;
+               }
+       } else {
+               /*
+                * A nameless chunk does not need its own output directory.
+                * The session's output directory will be used.
+                */
+               const bool reference_acquired =
+                               lttng_directory_handle_get(
+                                       session_output_directory);
+
+               assert(reference_acquired);
+               chunk_directory_handle = session_output_directory;
        }
        chunk->chunk_directory = chunk_directory_handle;
        chunk_directory_handle = NULL;
@@ -972,7 +1238,7 @@ int lttng_trace_chunk_unlink_file(struct lttng_trace_chunk *chunk,
        if (!chunk->credentials.is_set) {
                /*
                 * Fatal error, credentials must be set before a
-                * directory is created.
+                * file is unlinked.
                 */
                ERR("Credentials of trace chunk are unset: refusing to unlink file \"%s\"",
                                file_path);
@@ -999,12 +1265,50 @@ end:
        return status;
 }
 
-static
-void lttng_trace_chunk_move_to_completed(struct lttng_trace_chunk *trace_chunk)
+LTTNG_HIDDEN
+int lttng_trace_chunk_remove_subdirectory_recursive(struct lttng_trace_chunk *chunk,
+               const char *path)
 {
        int ret;
-       char *directory_to_rename = NULL;
-       bool free_directory_to_rename = false;
+       enum lttng_trace_chunk_status status = LTTNG_TRACE_CHUNK_STATUS_OK;
+
+       DBG("Recursively removing trace chunk directory \"%s\"", path);
+       pthread_mutex_lock(&chunk->lock);
+       if (!chunk->credentials.is_set) {
+               /*
+                * Fatal error, credentials must be set before a
+                * directory is removed.
+                */
+               ERR("Credentials of trace chunk are unset: refusing to recursively remove directory \"%s\"",
+                               path);
+               status = LTTNG_TRACE_CHUNK_STATUS_ERROR;
+               goto end;
+       }
+       if (!chunk->chunk_directory) {
+               ERR("Attempted to recursively remove trace chunk directory \"%s\" before setting the chunk output directory",
+                               path);
+               status = LTTNG_TRACE_CHUNK_STATUS_ERROR;
+               goto end;
+       }
+       ret = lttng_directory_handle_remove_subdirectory_recursive_as_user(
+                       chunk->chunk_directory, path,
+                       chunk->credentials.value.use_current_user ?
+                                       NULL : &chunk->credentials.value.user,
+                       LTTNG_DIRECTORY_HANDLE_SKIP_NON_EMPTY_FLAG);
+       if (ret < 0) {
+               status = LTTNG_TRACE_CHUNK_STATUS_ERROR;
+               goto end;
+       }
+end:
+       pthread_mutex_unlock(&chunk->lock);
+       return status;
+}
+
+static
+int lttng_trace_chunk_move_to_completed_post_release(
+               struct lttng_trace_chunk *trace_chunk)
+{
+       int ret = 0;
        char *archived_chunk_name = NULL;
        const uint64_t chunk_id = LTTNG_OPTIONAL_GET(trace_chunk->id);
        const time_t creation_timestamp =
@@ -1012,6 +1316,7 @@ void lttng_trace_chunk_move_to_completed(struct lttng_trace_chunk *trace_chunk)
        const time_t close_timestamp =
                        LTTNG_OPTIONAL_GET(trace_chunk->timestamp_close);
        struct lttng_directory_handle *archived_chunks_directory = NULL;
+       enum lttng_trace_chunk_status status;
 
        if (!trace_chunk->mode.is_set ||
                        trace_chunk->mode.value != TRACE_CHUNK_MODE_OWNER ||
@@ -1025,76 +1330,13 @@ void lttng_trace_chunk_move_to_completed(struct lttng_trace_chunk *trace_chunk)
 
        assert(trace_chunk->mode.value == TRACE_CHUNK_MODE_OWNER);
        assert(!trace_chunk->name_overridden);
-
-       /*
-        * The fist trace chunk of a session is directly output to the
-        * session's output folder. In this case, the top level directories
-        * must be moved to a temporary folder before that temporary directory
-        * is renamed to match the chunk's name.
-        */
-       if (chunk_id == 0) {
-               struct lttng_directory_handle *temporary_rename_directory =
-                               NULL;
-               size_t i, count = lttng_dynamic_pointer_array_get_count(
-                                         &trace_chunk->top_level_directories);
-
-               ret = lttng_directory_handle_create_subdirectory_as_user(
-                               trace_chunk->session_output_directory,
-                               DEFAULT_TEMPORARY_CHUNK_RENAME_DIRECTORY,
-                               DIR_CREATION_MODE,
-                               !trace_chunk->credentials.value.use_current_user ?
-                                       &trace_chunk->credentials.value.user : NULL);
-               if (ret) {
-                       PERROR("Failed to create temporary trace chunk rename directory \"%s\"",
-                                       DEFAULT_TEMPORARY_CHUNK_RENAME_DIRECTORY);
-               }
-
-               temporary_rename_directory = lttng_directory_handle_create_from_handle(
-                               DEFAULT_TEMPORARY_CHUNK_RENAME_DIRECTORY,
-                               trace_chunk->session_output_directory);
-               if (!temporary_rename_directory) {
-                       ERR("Failed to get handle to temporary trace chunk rename directory");
-                       goto end;
-               }
-
-               for (i = 0; i < count; i++) {
-                       const char *top_level_name =
-                                       lttng_dynamic_pointer_array_get_pointer(
-                                               &trace_chunk->top_level_directories, i);
-
-                       ret = lttng_directory_handle_rename_as_user(
-                                       trace_chunk->session_output_directory,
-                                       top_level_name,
-                                       temporary_rename_directory,
-                                       top_level_name,
-                                       LTTNG_OPTIONAL_GET(trace_chunk->credentials).use_current_user ?
-                                               NULL :
-                                               &trace_chunk->credentials.value.user);
-                       if (ret) {
-                               PERROR("Failed to move \"%s\" to temporary trace chunk rename directory",
-                                               top_level_name);
-                               lttng_directory_handle_put(
-                                               temporary_rename_directory);
-                               goto end;
-                       }
-               }
-               lttng_directory_handle_put(temporary_rename_directory);
-               directory_to_rename = DEFAULT_TEMPORARY_CHUNK_RENAME_DIRECTORY;
-               free_directory_to_rename = false;
-       } else {
-               directory_to_rename = generate_chunk_name(chunk_id,
-                               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;
-       }
+       assert(trace_chunk->path);
 
        archived_chunk_name = generate_chunk_name(chunk_id, creation_timestamp,
                        &close_timestamp);
        if (!archived_chunk_name) {
                ERR("Failed to generate archived trace chunk name while renaming trace chunk");
+               ret = -1;
                goto end;
        }
 
@@ -1116,12 +1358,29 @@ void lttng_trace_chunk_move_to_completed(struct lttng_trace_chunk *trace_chunk)
                        trace_chunk->session_output_directory);
        if (!archived_chunks_directory) {
                PERROR("Failed to get handle to archived trace chunks directory");
+               ret = -1;
                goto end;
        }
 
+       /*
+        * Make sure chunk is renamed to old directory if not already done by
+        * the creation of the next chunk. This happens if a rotation is
+        * performed while tracing is stopped.
+        */
+       if (!trace_chunk->path || strcmp(trace_chunk->path,
+                       DEFAULT_CHUNK_TMP_OLD_DIRECTORY)) {
+               status = lttng_trace_chunk_rename_path_no_lock(trace_chunk,
+                               DEFAULT_CHUNK_TMP_OLD_DIRECTORY);
+               if (status != LTTNG_TRACE_CHUNK_STATUS_OK) {
+                       ERR("Failed to rename chunk to %s", DEFAULT_CHUNK_TMP_OLD_DIRECTORY);
+                       ret = -1;
+                       goto end;
+               }
+       }
+
        ret = lttng_directory_handle_rename_as_user(
                        trace_chunk->session_output_directory,
-                       directory_to_rename,
+                       trace_chunk->path,
                        archived_chunks_directory,
                        archived_chunk_name,
                        LTTNG_OPTIONAL_GET(trace_chunk->credentials).use_current_user ?
@@ -1129,15 +1388,14 @@ void lttng_trace_chunk_move_to_completed(struct lttng_trace_chunk *trace_chunk)
                                &trace_chunk->credentials.value.user);
        if (ret) {
                PERROR("Failed to rename folder \"%s\" to \"%s\"",
-                               directory_to_rename, archived_chunk_name);
+                               trace_chunk->path,
+                               archived_chunk_name);
        }
 
 end:
        lttng_directory_handle_put(archived_chunks_directory);
        free(archived_chunk_name);
-       if (free_directory_to_rename) {
-               free(directory_to_rename);
-       }
+       return ret;
 }
 
 LTTNG_HIDDEN
@@ -1233,7 +1491,11 @@ void lttng_trace_chunk_release(struct urcu_ref *ref)
                        ref);
 
        if (chunk->close_command.is_set) {
-               close_command_funcs[chunk->close_command.value](chunk);
+               if (close_command_post_release_funcs[
+                               chunk->close_command.value](chunk)) {
+                       ERR("Trace chunk post-release command %s has failed.",
+                                       close_command_names[chunk->close_command.value]);
+               }
        }
 
        if (chunk->in_registry_element) {
@@ -1333,10 +1595,11 @@ lttng_trace_chunk_registry_element_create_from_chunk(
                chunk->chunk_directory = NULL;
        }
        /*
-        * The original chunk becomes invalid; the name attribute is transferred
-        * to the new chunk instance.
+        * The original chunk becomes invalid; the name and path attributes are
+        * transferred to the new chunk instance.
         */
        chunk->name = NULL;
+       chunk->path = NULL;
        element->chunk.in_registry_element = true;
 end:
        return element;
index 7135b01939fdbe50b1544a4d5bf6b347378986ce..c2fcd17e96059dc4ba584d3baa39ce23ae5e735f 100644 (file)
@@ -84,7 +84,8 @@ struct lttng_trace_chunk *lttng_trace_chunk_create_anonymous(void);
 LTTNG_HIDDEN
 struct lttng_trace_chunk *lttng_trace_chunk_create(
                uint64_t chunk_id,
-               time_t chunk_creation_time);
+               time_t chunk_creation_time,
+               const char *path);
 
 /*
  * Copy a trace chunk. The copy that is returned is always a _user_
@@ -123,6 +124,10 @@ LTTNG_HIDDEN
 enum lttng_trace_chunk_status lttng_trace_chunk_override_name(
                struct lttng_trace_chunk *chunk, const char *name);
 
+LTTNG_HIDDEN
+enum lttng_trace_chunk_status lttng_trace_chunk_rename_path(
+               struct lttng_trace_chunk *chunk, const char *path);
+
 LTTNG_HIDDEN
 enum lttng_trace_chunk_status lttng_trace_chunk_get_credentials(
                struct lttng_trace_chunk *chunk,
This page took 0.039804 seconds and 4 git commands to generate.