X-Git-Url: http://git.efficios.com/?p=lttng-tools.git;a=blobdiff_plain;f=src%2Fcommon%2Ftrace-chunk.c;h=c549f46b33c855334814355ef8a6e37f6cacadf2;hp=afba60b38e5c4301f8d322afb2062f1cbdfead67;hb=0e2d816a62eccd0d159ec254e87ff80a7e6cf1bb;hpb=c222b0167b6a89a1949875d0fe242772733c93af diff --git a/src/common/trace-chunk.c b/src/common/trace-chunk.c index afba60b38..c549f46b3 100644 --- a/src/common/trace-chunk.c +++ b/src/common/trace-chunk.c @@ -78,6 +78,11 @@ struct lttng_trace_chunk { * 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_overridden; @@ -87,8 +92,8 @@ struct lttng_trace_chunk { 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; }; @@ -111,6 +116,10 @@ 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 @@ -216,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); } @@ -343,23 +356,20 @@ struct lttng_trace_chunk *lttng_trace_chunk_copy( 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->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.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; - } + 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); @@ -473,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) { @@ -603,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) { @@ -638,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); @@ -662,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) { @@ -673,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); @@ -682,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; @@ -776,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; @@ -789,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); @@ -809,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; @@ -829,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; @@ -870,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; @@ -901,11 +1011,11 @@ 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.is_set) { + !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. @@ -923,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 ? @@ -938,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; } @@ -952,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 : @@ -962,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 { @@ -988,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 ? @@ -1000,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 : @@ -1024,9 +1133,7 @@ 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); @@ -1073,7 +1180,15 @@ 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: return status; @@ -1086,6 +1201,10 @@ const char *lttng_trace_chunk_command_type_get_name( 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(); } @@ -1202,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 @@ -1269,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; } }