default.c 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. #define _FASTWRITER_DEFAULT_C
  2. #define _GNU_SOURCE
  3. #define _XOPEN_SOURCE 600
  4. #define _POSIX_C_SOURCE 200112L
  5. #define _LARGEFILE64_SOURCE
  6. #include "config.h"
  7. #include <stdio.h>
  8. #include <stdlib.h>
  9. #include <string.h>
  10. #include <unistd.h>
  11. #include <limits.h>
  12. #include <errno.h>
  13. #include <pthread.h>
  14. #include <sys/types.h>
  15. #include <sys/stat.h>
  16. #include <sys/time.h>
  17. #include <fcntl.h>
  18. #ifdef HAVE_LINUX_FALLOC_H
  19. # include <linux/falloc.h>
  20. #endif /* HAVE_LINUX_FALLOC_H */
  21. #include "fastwriter.h"
  22. #include "private.h"
  23. #include "sysinfo.h"
  24. #include "default.h"
  25. #define SYNC_MODE
  26. #define HAVE_FALLOCATE
  27. #define EXT4_WRITEBLOCK 4194304
  28. #define EXT4_PREALLOCATE 1073741824
  29. typedef struct {
  30. int fd;
  31. size_t prior_size; /**< original size of file */
  32. size_t preallocated; /**< preallocated bytes */
  33. size_t wr_block; /**< minimal block of data to write */
  34. size_t pa_block; /**< preallocation setp */
  35. } fastwriter_default_t;
  36. int fastwriter_default_open(fastwriter_t *fw, const char *name, fastwriter_flags_t flags) {
  37. int err;
  38. char fs[16];
  39. int open_flags = (O_CREAT|O_WRONLY|O_NOATIME|O_LARGEFILE);
  40. int open_mode = (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
  41. #ifdef SYNC_MODE
  42. open_flags |= O_DIRECT;//|O_SYNC;
  43. #endif /* SYNC_MODE */
  44. fastwriter_default_t *ctx;
  45. err = get_file_fs(name, sizeof(fs) - 1, fs);
  46. if (err) return err;
  47. ctx = (fastwriter_default_t*)malloc(sizeof(fastwriter_default_t));
  48. if (!ctx) return ENOMEM;
  49. memset(ctx, 0, sizeof(fastwriter_default_t));
  50. fw->ctx = ctx;
  51. if (!strcmp(fs, "raw")) {
  52. ctx->wr_block = EXT4_WRITEBLOCK;
  53. ctx->pa_block = 0;
  54. } else if (!strcmp(fs, "ext4")) {
  55. ctx->wr_block = EXT4_WRITEBLOCK;
  56. ctx->pa_block = EXT4_PREALLOCATE;
  57. } else if (!strcmp(fs, "btrfs")) {
  58. ctx->wr_block = EXT4_WRITEBLOCK;
  59. ctx->pa_block = EXT4_PREALLOCATE;
  60. } else if (!strcmp(fs, "xfs")) {
  61. ctx->wr_block = EXT4_WRITEBLOCK;
  62. ctx->pa_block = EXT4_PREALLOCATE;
  63. } else {
  64. ctx->wr_block = EXT4_WRITEBLOCK;
  65. ctx->pa_block = 0;
  66. }
  67. if (flags&FASTWRITER_FLAGS_OVERWRITE)
  68. open_flags |= O_TRUNC;
  69. ctx->fd = open(name, open_flags, open_mode);
  70. if (ctx->fd < 0) return errno;
  71. ctx->prior_size = 0;
  72. #ifndef HAVE_LINUX_FALLOC_H
  73. if (((open_flags&FASTWRITER_FLAGS_OVERWRITE)==0)&&(strcmp(fs, "raw"))) {
  74. ctx->prior_size = lseek(ctx->fd, 0, SEEK_END);
  75. }
  76. #endif /* HAVE_LINUX_FALLOC_H */
  77. ctx->preallocated = 0;
  78. return 0;
  79. }
  80. void fastwriter_default_close(fastwriter_t *fw) {
  81. if (fw->ctx) {
  82. fastwriter_default_t *ctx = (fastwriter_default_t*)fw->ctx;
  83. if (ctx->fd >= 0) {
  84. #ifndef HAVE_LINUX_FALLOC_H
  85. if (ctx->prior_size) {
  86. ftrucate(ctx->fd, ctx->prior_size + fw->written);
  87. }
  88. #endif /* HAVE_LINUX_FALLOC_H */
  89. close(ctx->fd);
  90. }
  91. free(ctx);
  92. fw->ctx = NULL;
  93. }
  94. }
  95. int fastwriter_default_write(fastwriter_t *fw, fastwriter_write_flags_t flags, size_t size, void *data, size_t *written) {
  96. size_t sum = 0;
  97. ssize_t res;
  98. fastwriter_default_t *ctx = (fastwriter_default_t*)fw->ctx;
  99. if ((flags&FASTWRITER_WRITE_FLAG_FORCE)==0) {
  100. if (size < ctx->wr_block) {
  101. *written = 0;
  102. return 0;
  103. }
  104. size -= size % ctx->wr_block;
  105. }
  106. if ((ctx->pa_block)&&((fw->written + size) > ctx->preallocated)) {
  107. #ifdef HAVE_LINUX_FALLOC_H
  108. if (fallocate(ctx->fd, FALLOC_FL_KEEP_SIZE, ctx->preallocated, ctx->pa_block)) {
  109. #else /* HAVE_LINUX_FALLOC_H */
  110. if (posix_fallocate(ctx->fd, ctx->preallocated, ctx->pa_block)) {
  111. #endif /* HAVE_LINUX_FALLOC_H */
  112. ctx->pa_block = 0;
  113. } else {
  114. ctx->preallocated += ctx->pa_block;
  115. }
  116. }
  117. do {
  118. res = write(ctx->fd, data, size);
  119. if (res < 0) {
  120. *written = sum;
  121. return errno;
  122. }
  123. sum += res;
  124. } while (sum < size);
  125. #ifdef SYNC_MODE
  126. posix_fadvise(ctx->fd, fw->written, size, POSIX_FADV_DONTNEED);
  127. #endif /* SYNC_MODE */
  128. *written = size;
  129. return 0;
  130. }