rrdenginelib.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  1. // SPDX-License-Identifier: GPL-3.0-or-later
  2. #include "rrdengine.h"
  3. #define BUFSIZE (512)
  4. /* Caller must hold descriptor lock */
  5. void print_page_cache_descr(struct rrdeng_page_descr *descr)
  6. {
  7. struct page_cache_descr *pg_cache_descr = descr->pg_cache_descr;
  8. char uuid_str[UUID_STR_LEN];
  9. char str[BUFSIZE + 1];
  10. int pos = 0;
  11. uuid_unparse_lower(*descr->id, uuid_str);
  12. pos += snprintfz(str, BUFSIZE - pos, "page(%p) id=%s\n"
  13. "--->len:%"PRIu32" time:%"PRIu64"->%"PRIu64" xt_offset:",
  14. pg_cache_descr->page, uuid_str,
  15. descr->page_length,
  16. (uint64_t)descr->start_time,
  17. (uint64_t)descr->end_time);
  18. if (!descr->extent) {
  19. pos += snprintfz(str + pos, BUFSIZE - pos, "N/A");
  20. } else {
  21. pos += snprintfz(str + pos, BUFSIZE - pos, "%"PRIu64, descr->extent->offset);
  22. }
  23. snprintfz(str + pos, BUFSIZE - pos, " flags:0x%2.2lX refcnt:%u\n\n", pg_cache_descr->flags, pg_cache_descr->refcnt);
  24. debug(D_RRDENGINE, "%s", str);
  25. }
  26. void print_page_descr(struct rrdeng_page_descr *descr)
  27. {
  28. char uuid_str[UUID_STR_LEN];
  29. char str[BUFSIZE + 1];
  30. int pos = 0;
  31. uuid_unparse_lower(*descr->id, uuid_str);
  32. pos += snprintfz(str, BUFSIZE - pos, "id=%s\n"
  33. "--->len:%"PRIu32" time:%"PRIu64"->%"PRIu64" xt_offset:",
  34. uuid_str,
  35. descr->page_length,
  36. (uint64_t)descr->start_time,
  37. (uint64_t)descr->end_time);
  38. if (!descr->extent) {
  39. pos += snprintfz(str + pos, BUFSIZE - pos, "N/A");
  40. } else {
  41. pos += snprintfz(str + pos, BUFSIZE - pos, "%"PRIu64, descr->extent->offset);
  42. }
  43. snprintfz(str + pos, BUFSIZE - pos, "\n\n");
  44. fputs(str, stderr);
  45. }
  46. int check_file_properties(uv_file file, uint64_t *file_size, size_t min_size)
  47. {
  48. int ret;
  49. uv_fs_t req;
  50. uv_stat_t* s;
  51. ret = uv_fs_fstat(NULL, &req, file, NULL);
  52. if (ret < 0) {
  53. fatal("uv_fs_fstat: %s\n", uv_strerror(ret));
  54. }
  55. fatal_assert(req.result == 0);
  56. s = req.ptr;
  57. if (!(s->st_mode & S_IFREG)) {
  58. error("Not a regular file.\n");
  59. uv_fs_req_cleanup(&req);
  60. return UV_EINVAL;
  61. }
  62. if (s->st_size < min_size) {
  63. error("File length is too short.\n");
  64. uv_fs_req_cleanup(&req);
  65. return UV_EINVAL;
  66. }
  67. *file_size = s->st_size;
  68. uv_fs_req_cleanup(&req);
  69. return 0;
  70. }
  71. /**
  72. * Open file for I/O.
  73. *
  74. * @param path The full path of the file.
  75. * @param flags Same flags as the open() system call uses.
  76. * @param file On success sets (*file) to be the uv_file that was opened.
  77. * @param direct Tries to open a file in direct I/O mode when direct=1, falls back to buffered mode if not possible.
  78. * @return Returns UV error number that is < 0 on failure. 0 on success.
  79. */
  80. int open_file_for_io(char *path, int flags, uv_file *file, int direct)
  81. {
  82. uv_fs_t req;
  83. int fd = -1, current_flags;
  84. fatal_assert(0 == direct || 1 == direct);
  85. for ( ; direct >= 0 ; --direct) {
  86. #ifdef __APPLE__
  87. /* Apple OS does not support O_DIRECT */
  88. direct = 0;
  89. #endif
  90. current_flags = flags;
  91. if (direct) {
  92. current_flags |= O_DIRECT;
  93. }
  94. fd = uv_fs_open(NULL, &req, path, current_flags, S_IRUSR | S_IWUSR, NULL);
  95. if (fd < 0) {
  96. if ((direct) && (UV_EINVAL == fd)) {
  97. error("File \"%s\" does not support direct I/O, falling back to buffered I/O.", path);
  98. } else {
  99. error("Failed to open file \"%s\".", path);
  100. --direct; /* break the loop */
  101. }
  102. } else {
  103. fatal_assert(req.result >= 0);
  104. *file = req.result;
  105. #ifdef __APPLE__
  106. info("Disabling OS X caching for file \"%s\".", path);
  107. fcntl(fd, F_NOCACHE, 1);
  108. #endif
  109. --direct; /* break the loop */
  110. }
  111. uv_fs_req_cleanup(&req);
  112. }
  113. return fd;
  114. }
  115. char *get_rrdeng_statistics(struct rrdengine_instance *ctx, char *str, size_t size)
  116. {
  117. struct page_cache *pg_cache;
  118. pg_cache = &ctx->pg_cache;
  119. snprintfz(str, size,
  120. "metric_API_producers: %ld\n"
  121. "metric_API_consumers: %ld\n"
  122. "page_cache_total_pages: %ld\n"
  123. "page_cache_descriptors: %ld\n"
  124. "page_cache_populated_pages: %ld\n"
  125. "page_cache_committed_pages: %ld\n"
  126. "page_cache_insertions: %ld\n"
  127. "page_cache_deletions: %ld\n"
  128. "page_cache_hits: %ld\n"
  129. "page_cache_misses: %ld\n"
  130. "page_cache_backfills: %ld\n"
  131. "page_cache_evictions: %ld\n"
  132. "compress_before_bytes: %ld\n"
  133. "compress_after_bytes: %ld\n"
  134. "decompress_before_bytes: %ld\n"
  135. "decompress_after_bytes: %ld\n"
  136. "io_write_bytes: %ld\n"
  137. "io_write_requests: %ld\n"
  138. "io_read_bytes: %ld\n"
  139. "io_read_requests: %ld\n"
  140. "io_write_extent_bytes: %ld\n"
  141. "io_write_extents: %ld\n"
  142. "io_read_extent_bytes: %ld\n"
  143. "io_read_extents: %ld\n"
  144. "datafile_creations: %ld\n"
  145. "datafile_deletions: %ld\n"
  146. "journalfile_creations: %ld\n"
  147. "journalfile_deletions: %ld\n"
  148. "io_errors: %ld\n"
  149. "fs_errors: %ld\n"
  150. "global_io_errors: %ld\n"
  151. "global_fs_errors: %ld\n"
  152. "rrdeng_reserved_file_descriptors: %ld\n"
  153. "pg_cache_over_half_dirty_events: %ld\n"
  154. "global_pg_cache_over_half_dirty_events: %ld\n"
  155. "flushing_pressure_page_deletions: %ld\n"
  156. "global_flushing_pressure_page_deletions: %ld\n",
  157. (long)ctx->stats.metric_API_producers,
  158. (long)ctx->stats.metric_API_consumers,
  159. (long)pg_cache->page_descriptors,
  160. (long)ctx->stats.page_cache_descriptors,
  161. (long)pg_cache->populated_pages,
  162. (long)pg_cache->committed_page_index.nr_committed_pages,
  163. (long)ctx->stats.pg_cache_insertions,
  164. (long)ctx->stats.pg_cache_deletions,
  165. (long)ctx->stats.pg_cache_hits,
  166. (long)ctx->stats.pg_cache_misses,
  167. (long)ctx->stats.pg_cache_backfills,
  168. (long)ctx->stats.pg_cache_evictions,
  169. (long)ctx->stats.before_compress_bytes,
  170. (long)ctx->stats.after_compress_bytes,
  171. (long)ctx->stats.before_decompress_bytes,
  172. (long)ctx->stats.after_decompress_bytes,
  173. (long)ctx->stats.io_write_bytes,
  174. (long)ctx->stats.io_write_requests,
  175. (long)ctx->stats.io_read_bytes,
  176. (long)ctx->stats.io_read_requests,
  177. (long)ctx->stats.io_write_extent_bytes,
  178. (long)ctx->stats.io_write_extents,
  179. (long)ctx->stats.io_read_extent_bytes,
  180. (long)ctx->stats.io_read_extents,
  181. (long)ctx->stats.datafile_creations,
  182. (long)ctx->stats.datafile_deletions,
  183. (long)ctx->stats.journalfile_creations,
  184. (long)ctx->stats.journalfile_deletions,
  185. (long)ctx->stats.io_errors,
  186. (long)ctx->stats.fs_errors,
  187. (long)global_io_errors,
  188. (long)global_fs_errors,
  189. (long)rrdeng_reserved_file_descriptors,
  190. (long)ctx->stats.pg_cache_over_half_dirty_events,
  191. (long)global_pg_cache_over_half_dirty_events,
  192. (long)ctx->stats.flushing_pressure_page_deletions,
  193. (long)global_flushing_pressure_page_deletions
  194. );
  195. return str;
  196. }
  197. int is_legacy_child(const char *machine_guid)
  198. {
  199. uuid_t uuid;
  200. char dbengine_file[FILENAME_MAX+1];
  201. if (unlikely(!strcmp(machine_guid, "unittest-dbengine") || !strcmp(machine_guid, "dbengine-dataset") ||
  202. !strcmp(machine_guid, "dbengine-stress-test"))) {
  203. return 1;
  204. }
  205. if (!uuid_parse(machine_guid, uuid)) {
  206. uv_fs_t stat_req;
  207. snprintfz(dbengine_file, FILENAME_MAX, "%s/%s/dbengine", netdata_configured_cache_dir, machine_guid);
  208. int rc = uv_fs_stat(NULL, &stat_req, dbengine_file, NULL);
  209. if (likely(rc == 0 && ((stat_req.statbuf.st_mode & S_IFMT) == S_IFDIR))) {
  210. //info("Found legacy engine folder \"%s\"", dbengine_file);
  211. return 1;
  212. }
  213. }
  214. return 0;
  215. }
  216. int count_legacy_children(char *dbfiles_path)
  217. {
  218. int ret;
  219. uv_fs_t req;
  220. uv_dirent_t dent;
  221. int legacy_engines = 0;
  222. ret = uv_fs_scandir(NULL, &req, dbfiles_path, 0, NULL);
  223. if (ret < 0) {
  224. uv_fs_req_cleanup(&req);
  225. error("uv_fs_scandir(%s): %s", dbfiles_path, uv_strerror(ret));
  226. return ret;
  227. }
  228. while(UV_EOF != uv_fs_scandir_next(&req, &dent)) {
  229. if (dent.type == UV_DIRENT_DIR) {
  230. if (is_legacy_child(dent.name))
  231. legacy_engines++;
  232. }
  233. }
  234. uv_fs_req_cleanup(&req);
  235. return legacy_engines;
  236. }
  237. int compute_multidb_diskspace()
  238. {
  239. char multidb_disk_space_file[FILENAME_MAX + 1];
  240. FILE *fp;
  241. int computed_multidb_disk_quota_mb = -1;
  242. snprintfz(multidb_disk_space_file, FILENAME_MAX, "%s/dbengine_multihost_size", netdata_configured_varlib_dir);
  243. fp = fopen(multidb_disk_space_file, "r");
  244. if (likely(fp)) {
  245. int rc = fscanf(fp, "%d", &computed_multidb_disk_quota_mb);
  246. fclose(fp);
  247. if (unlikely(rc != 1 || computed_multidb_disk_quota_mb < RRDENG_MIN_DISK_SPACE_MB)) {
  248. errno = 0;
  249. error("File '%s' contains invalid input, it will be rebuild", multidb_disk_space_file);
  250. computed_multidb_disk_quota_mb = -1;
  251. }
  252. }
  253. if (computed_multidb_disk_quota_mb == -1) {
  254. int rc = count_legacy_children(netdata_configured_cache_dir);
  255. if (likely(rc >= 0)) {
  256. computed_multidb_disk_quota_mb = (rc + 1) * default_rrdeng_disk_quota_mb;
  257. info("Found %d legacy dbengines, setting multidb diskspace to %dMB", rc, computed_multidb_disk_quota_mb);
  258. fp = fopen(multidb_disk_space_file, "w");
  259. if (likely(fp)) {
  260. fprintf(fp, "%d", computed_multidb_disk_quota_mb);
  261. info("Created file '%s' to store the computed value", multidb_disk_space_file);
  262. fclose(fp);
  263. } else
  264. error("Failed to store the default multidb disk quota size on '%s'", multidb_disk_space_file);
  265. }
  266. else
  267. computed_multidb_disk_quota_mb = default_rrdeng_disk_quota_mb;
  268. }
  269. return computed_multidb_disk_quota_mb;
  270. }