rrdenginelib.c 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  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, const char *msg, bool log_debug)
  6. //{
  7. // if(log_debug && !(debug_flags & D_RRDENGINE))
  8. // return;
  9. //
  10. // BUFFER *wb = buffer_create(512);
  11. //
  12. // if(!descr) {
  13. // buffer_sprintf(wb, "DBENGINE: %s : descr is NULL", msg);
  14. // }
  15. // else {
  16. // struct page_cache_descr *pg_cache_descr = descr->pg_cache_descr;
  17. // char uuid_str[UUID_STR_LEN];
  18. //
  19. // uuid_unparse_lower(*descr->id, uuid_str);
  20. // buffer_sprintf(wb, "DBENGINE: %s : page(%p) metric:%s, len:%"PRIu32", time:%"PRIu64"->%"PRIu64", update_every:%u, type:%u, xt_offset:",
  21. // msg,
  22. // pg_cache_descr->page, uuid_str,
  23. // descr->page_length,
  24. // (uint64_t)descr->start_time_ut,
  25. // (uint64_t)descr->end_time_ut,
  26. // (uint32_t)descr->update_every_s,
  27. // (uint32_t)descr->type
  28. // );
  29. // if (!descr->extent) {
  30. // buffer_strcat(wb, "N/A");
  31. // } else {
  32. // buffer_sprintf(wb, "%"PRIu64, descr->extent->offset);
  33. // }
  34. //
  35. // buffer_sprintf(wb, ", flags:0x%2.2lX refcnt:%u", pg_cache_descr->flags, pg_cache_descr->refcnt);
  36. // }
  37. //
  38. // if(log_debug)
  39. // debug(D_RRDENGINE, "%s", buffer_tostring(wb));
  40. // else
  41. // internal_error(true, "%s", buffer_tostring(wb));
  42. //
  43. // buffer_free(wb);
  44. //}
  45. //
  46. //void print_page_descr(struct rrdeng_page_descr *descr)
  47. //{
  48. // char uuid_str[UUID_STR_LEN];
  49. // char str[BUFSIZE + 1];
  50. // int pos = 0;
  51. //
  52. // uuid_unparse_lower(*descr->id, uuid_str);
  53. // pos += snprintfz(str, BUFSIZE - pos, "id=%s\n"
  54. // "--->len:%"PRIu32" time:%"PRIu64"->%"PRIu64" xt_offset:",
  55. // uuid_str,
  56. // descr->page_length,
  57. // (uint64_t)descr->start_time_ut,
  58. // (uint64_t)descr->end_time_ut);
  59. // if (!descr->extent) {
  60. // pos += snprintfz(str + pos, BUFSIZE - pos, "N/A");
  61. // } else {
  62. // pos += snprintfz(str + pos, BUFSIZE - pos, "%"PRIu64, descr->extent->offset);
  63. // }
  64. // snprintfz(str + pos, BUFSIZE - pos, "\n\n");
  65. // fputs(str, stderr);
  66. //}
  67. int check_file_properties(uv_file file, uint64_t *file_size, size_t min_size)
  68. {
  69. int ret;
  70. uv_fs_t req;
  71. uv_stat_t* s;
  72. ret = uv_fs_fstat(NULL, &req, file, NULL);
  73. if (ret < 0) {
  74. fatal("uv_fs_fstat: %s\n", uv_strerror(ret));
  75. }
  76. fatal_assert(req.result == 0);
  77. s = req.ptr;
  78. if (!(s->st_mode & S_IFREG)) {
  79. error("Not a regular file.\n");
  80. uv_fs_req_cleanup(&req);
  81. return UV_EINVAL;
  82. }
  83. if (s->st_size < min_size) {
  84. error("File length is too short.\n");
  85. uv_fs_req_cleanup(&req);
  86. return UV_EINVAL;
  87. }
  88. *file_size = s->st_size;
  89. uv_fs_req_cleanup(&req);
  90. return 0;
  91. }
  92. /**
  93. * Open file for I/O.
  94. *
  95. * @param path The full path of the file.
  96. * @param flags Same flags as the open() system call uses.
  97. * @param file On success sets (*file) to be the uv_file that was opened.
  98. * @param direct Tries to open a file in direct I/O mode when direct=1, falls back to buffered mode if not possible.
  99. * @return Returns UV error number that is < 0 on failure. 0 on success.
  100. */
  101. int open_file_for_io(char *path, int flags, uv_file *file, int direct)
  102. {
  103. uv_fs_t req;
  104. int fd = -1, current_flags;
  105. fatal_assert(0 == direct || 1 == direct);
  106. for ( ; direct >= 0 ; --direct) {
  107. #ifdef __APPLE__
  108. /* Apple OS does not support O_DIRECT */
  109. direct = 0;
  110. #endif
  111. current_flags = flags;
  112. if (direct) {
  113. current_flags |= O_DIRECT;
  114. }
  115. fd = uv_fs_open(NULL, &req, path, current_flags, S_IRUSR | S_IWUSR, NULL);
  116. if (fd < 0) {
  117. if ((direct) && (UV_EINVAL == fd)) {
  118. error("File \"%s\" does not support direct I/O, falling back to buffered I/O.", path);
  119. } else {
  120. error("Failed to open file \"%s\".", path);
  121. --direct; /* break the loop */
  122. }
  123. } else {
  124. fatal_assert(req.result >= 0);
  125. *file = req.result;
  126. #ifdef __APPLE__
  127. info("Disabling OS X caching for file \"%s\".", path);
  128. fcntl(fd, F_NOCACHE, 1);
  129. #endif
  130. --direct; /* break the loop */
  131. }
  132. uv_fs_req_cleanup(&req);
  133. }
  134. return fd;
  135. }
  136. int is_legacy_child(const char *machine_guid)
  137. {
  138. uuid_t uuid;
  139. char dbengine_file[FILENAME_MAX+1];
  140. if (unlikely(!strcmp(machine_guid, "unittest-dbengine") || !strcmp(machine_guid, "dbengine-dataset") ||
  141. !strcmp(machine_guid, "dbengine-stress-test"))) {
  142. return 1;
  143. }
  144. if (!uuid_parse(machine_guid, uuid)) {
  145. uv_fs_t stat_req;
  146. snprintfz(dbengine_file, FILENAME_MAX, "%s/%s/dbengine", netdata_configured_cache_dir, machine_guid);
  147. int rc = uv_fs_stat(NULL, &stat_req, dbengine_file, NULL);
  148. if (likely(rc == 0 && ((stat_req.statbuf.st_mode & S_IFMT) == S_IFDIR))) {
  149. //info("Found legacy engine folder \"%s\"", dbengine_file);
  150. return 1;
  151. }
  152. }
  153. return 0;
  154. }
  155. int count_legacy_children(char *dbfiles_path)
  156. {
  157. int ret;
  158. uv_fs_t req;
  159. uv_dirent_t dent;
  160. int legacy_engines = 0;
  161. ret = uv_fs_scandir(NULL, &req, dbfiles_path, 0, NULL);
  162. if (ret < 0) {
  163. uv_fs_req_cleanup(&req);
  164. error("uv_fs_scandir(%s): %s", dbfiles_path, uv_strerror(ret));
  165. return ret;
  166. }
  167. while(UV_EOF != uv_fs_scandir_next(&req, &dent)) {
  168. if (dent.type == UV_DIRENT_DIR) {
  169. if (is_legacy_child(dent.name))
  170. legacy_engines++;
  171. }
  172. }
  173. uv_fs_req_cleanup(&req);
  174. return legacy_engines;
  175. }
  176. int compute_multidb_diskspace()
  177. {
  178. char multidb_disk_space_file[FILENAME_MAX + 1];
  179. FILE *fp;
  180. int computed_multidb_disk_quota_mb = -1;
  181. snprintfz(multidb_disk_space_file, FILENAME_MAX, "%s/dbengine_multihost_size", netdata_configured_varlib_dir);
  182. fp = fopen(multidb_disk_space_file, "r");
  183. if (likely(fp)) {
  184. int rc = fscanf(fp, "%d", &computed_multidb_disk_quota_mb);
  185. fclose(fp);
  186. if (unlikely(rc != 1 || computed_multidb_disk_quota_mb < RRDENG_MIN_DISK_SPACE_MB)) {
  187. errno = 0;
  188. error("File '%s' contains invalid input, it will be rebuild", multidb_disk_space_file);
  189. computed_multidb_disk_quota_mb = -1;
  190. }
  191. }
  192. if (computed_multidb_disk_quota_mb == -1) {
  193. int rc = count_legacy_children(netdata_configured_cache_dir);
  194. if (likely(rc >= 0)) {
  195. computed_multidb_disk_quota_mb = (rc + 1) * default_rrdeng_disk_quota_mb;
  196. info("Found %d legacy dbengines, setting multidb diskspace to %dMB", rc, computed_multidb_disk_quota_mb);
  197. fp = fopen(multidb_disk_space_file, "w");
  198. if (likely(fp)) {
  199. fprintf(fp, "%d", computed_multidb_disk_quota_mb);
  200. info("Created file '%s' to store the computed value", multidb_disk_space_file);
  201. fclose(fp);
  202. } else
  203. error("Failed to store the default multidb disk quota size on '%s'", multidb_disk_space_file);
  204. }
  205. else
  206. computed_multidb_disk_quota_mb = default_rrdeng_disk_quota_mb;
  207. }
  208. return computed_multidb_disk_quota_mb;
  209. }