2 * SPDX-License-Identifier: MIT
4 * Copyright 2019 Francis Deslauriers <francis.deslauriers@efficios.com>
6 * Babeltrace - File descriptor cache
9 #define BT_LOG_OUTPUT_LEVEL (fdc->log_level)
10 #define BT_LOG_TAG "FD-CACHE"
11 #include "logging/log.h"
15 #include <sys/types.h>
19 #include "common/assert.h"
27 struct fd_handle_internal
{
28 struct bt_fd_cache_handle fd_handle
;
34 void fd_cache_handle_internal_destroy(
35 struct fd_handle_internal
*internal_fd
)
41 if (internal_fd
->fd_handle
.fd
>= 0) {
42 close(internal_fd
->fd_handle
.fd
);
43 internal_fd
->fd_handle
.fd
= -1;
51 * Using simple hash algorithm found on stackoverflow:
52 * https://stackoverflow.com/questions/664014/
55 uint64_t hash_uint64_t(uint64_t x
) {
56 x
= (x
^ (x
>> 30)) * UINT64_C(0xbf58476d1ce4e5b9);
57 x
= (x
^ (x
>> 27)) * UINT64_C(0x94d049bb133111eb);
63 guint
file_key_hash(gconstpointer v
)
65 const struct file_key
*fk
= v
;
66 return hash_uint64_t(fk
->dev
) ^ hash_uint64_t(fk
->ino
);
70 gboolean
file_key_equal(gconstpointer v1
, gconstpointer v2
)
72 const struct file_key
*fk1
= v1
;
73 const struct file_key
*fk2
= v2
;
75 return (fk1
->dev
== fk2
->dev
) && (fk1
->ino
== fk2
->ino
);
79 void file_key_destroy(gpointer data
)
81 struct file_key
*fk
= data
;
86 int bt_fd_cache_init(struct bt_fd_cache
*fdc
, int log_level
)
90 fdc
->log_level
= log_level
;
91 fdc
->cache
= g_hash_table_new_full(file_key_hash
, file_key_equal
,
92 file_key_destroy
, (GDestroyNotify
) fd_cache_handle_internal_destroy
);
101 void bt_fd_cache_fini(struct bt_fd_cache
*fdc
)
108 * All handle should have been removed for the hashtable at this point.
110 BT_ASSERT(g_hash_table_size(fdc
->cache
) == 0);
111 g_hash_table_destroy(fdc
->cache
);
118 struct bt_fd_cache_handle
*bt_fd_cache_get_handle(struct bt_fd_cache
*fdc
,
121 struct fd_handle_internal
*fd_internal
= NULL
;
126 ret
= stat(path
, &statbuf
);
129 * This is not necessarily an error as we sometimes try to open
130 * files to see if they exist. Log the error as DEBUG severity
133 BT_LOGD_ERRNO("Failed to stat file", ": path=%s", path
);
138 * Use the device number and inode number to uniquely identify a file.
139 * Even if the file has the same path, it may have been replaced so we
140 * must open a new FD for it. This replacement of file is more likely
141 * to happen with a lttng-live source component.
143 fk
.dev
= statbuf
.st_dev
;
144 fk
.ino
= statbuf
.st_ino
;
146 fd_internal
= g_hash_table_lookup(fdc
->cache
, &fk
);
148 struct file_key
*file_key
;
150 fd
= open(path
, O_RDONLY
);
152 BT_LOGE_ERRNO("Failed to open file", "path=%s", path
);
156 fd_internal
= g_new0(struct fd_handle_internal
, 1);
158 BT_LOGE_STR("Failed to allocate internal FD handle.");
162 file_key
= g_new0(struct file_key
, 1);
164 BT_LOGE_STR("Failed to allocate file key.");
170 fd_internal
->fd_handle
.fd
= fd
;
171 fd_internal
->ref_count
= 0;
172 fd_internal
->key
= file_key
;
174 /* Insert the newly created fd handle. */
175 g_hash_table_insert(fdc
->cache
, fd_internal
->key
, fd_internal
);
178 fd_internal
->ref_count
++;
183 * Close file descriptor if it was open() and we are currently on error
189 BT_LOGE_ERRNO("Failed to close file descriptor",
190 ": fd=%i, path=%s", fd
, path
);
194 fd_cache_handle_internal_destroy(fd_internal
);
197 return (struct bt_fd_cache_handle
*) fd_internal
;
201 void bt_fd_cache_put_handle(struct bt_fd_cache
*fdc
,
202 struct bt_fd_cache_handle
*handle
)
204 struct fd_handle_internal
*fd_internal
;
210 fd_internal
= (struct fd_handle_internal
*) handle
;
212 BT_ASSERT(fd_internal
->ref_count
> 0);
214 if (fd_internal
->ref_count
> 1) {
215 fd_internal
->ref_count
--;
220 close_ret
= close(fd_internal
->fd_handle
.fd
);
221 if (close_ret
== -1) {
222 BT_LOGE_ERRNO("Failed to close file descriptor",
223 ": fd=%d", fd_internal
->fd_handle
.fd
);
225 ret
= g_hash_table_remove(fdc
->cache
, fd_internal
->key
);