1 /*- 2 * Copyright (c) 2014-2018 MongoDB, Inc. 3 * Copyright (c) 2008-2014 WiredTiger, Inc. 4 * All rights reserved. 5 * 6 * See the file LICENSE for redistribution information. 7 */ 8 9 #define WT_SYSCALL(call, ret) do { \ 10 /* \ 11 * A call returning 0 indicates success; any call where \ 12 * 0 is not the only successful return must provide an \ 13 * expression evaluating to 0 in all successful cases. \ 14 * \ 15 * XXX \ 16 * Casting the call's return to int is because CentOS 7.3.1611 \ 17 * complains about syscall returning a long and the loss of \ 18 * integer precision in the assignment to ret. The cast should \ 19 * be a no-op everywhere. \ 20 */ \ 21 if (((ret) = (int)(call)) == 0) \ 22 break; \ 23 /* \ 24 * The call's error was either returned by the call or \ 25 * is in errno, and there are cases where it depends on \ 26 * the software release as to which it is (for example, \ 27 * posix_fadvise on FreeBSD and OS X). Failing calls \ 28 * must either return a non-zero error value, or -1 if \ 29 * the error value is in errno. (The WiredTiger errno \ 30 * function returns WT_ERROR if errno is 0, which isn't \ 31 * ideal but won't discard the failure.) \ 32 */ \ 33 if ((ret) == -1) \ 34 (ret) = __wt_errno(); \ 35 } while (0) 36 37 #define WT_RETRY_MAX 10 38 39 #define WT_SYSCALL_RETRY(call, ret) do { \ 40 int __retry; \ 41 for (__retry = 0; __retry < WT_RETRY_MAX; ++__retry) { \ 42 WT_SYSCALL(call, ret); \ 43 switch (ret) { \ 44 case EAGAIN: \ 45 case EBUSY: \ 46 case EINTR: \ 47 case EIO: \ 48 case EMFILE: \ 49 case ENFILE: \ 50 case ENOSPC: \ 51 __wt_sleep(0L, 50000L); \ 52 continue; \ 53 default: \ 54 break; \ 55 } \ 56 break; \ 57 } \ 58 } while (0) 59 60 #define WT_TIMEDIFF_NS(end, begin) \ 61 (WT_BILLION * (uint64_t)((end).tv_sec - (begin).tv_sec) + \ 62 (uint64_t)(end).tv_nsec - (uint64_t)(begin).tv_nsec) 63 #define WT_TIMEDIFF_US(end, begin) \ 64 (WT_TIMEDIFF_NS((end), (begin)) / WT_THOUSAND) 65 #define WT_TIMEDIFF_MS(end, begin) \ 66 (WT_TIMEDIFF_NS((end), (begin)) / WT_MILLION) 67 #define WT_TIMEDIFF_SEC(end, begin) \ 68 (WT_TIMEDIFF_NS((end), (begin)) / WT_BILLION) 69 70 #define WT_CLOCKDIFF_NS(end, begin) \ 71 (__wt_clock_to_nsec(end, begin)) 72 #define WT_CLOCKDIFF_US(end, begin) \ 73 (WT_CLOCKDIFF_NS(end, begin) / WT_THOUSAND) 74 #define WT_CLOCKDIFF_MS(end, begin) \ 75 (WT_CLOCKDIFF_NS(end, begin) / WT_MILLION) 76 #define WT_CLOCKDIFF_SEC(end, begin) \ 77 (WT_CLOCKDIFF_NS(end, begin) / WT_BILLION) 78 79 #define WT_TIMECMP(t1, t2) \ 80 ((t1).tv_sec < (t2).tv_sec ? -1 : \ 81 (t1).tv_sec == (t2).tv_sec ? \ 82 (t1).tv_nsec < (t2).tv_nsec ? -1 : \ 83 (t1).tv_nsec == (t2).tv_nsec ? 0 : 1 : 1) 84 85 /* 86 * Macros to ensure a file handle is inserted or removed from both the main and 87 * the hashed queue, used by connection-level and in-memory data structures. 88 */ 89 #define WT_FILE_HANDLE_INSERT(h, fh, bucket) do { \ 90 TAILQ_INSERT_HEAD(&(h)->fhqh, fh, q); \ 91 TAILQ_INSERT_HEAD(&(h)->fhhash[bucket], fh, hashq); \ 92 } while (0) 93 94 #define WT_FILE_HANDLE_REMOVE(h, fh, bucket) do { \ 95 TAILQ_REMOVE(&(h)->fhqh, fh, q); \ 96 TAILQ_REMOVE(&(h)->fhhash[bucket], fh, hashq); \ 97 } while (0) 98 99 struct __wt_fh { 100 /* 101 * There is a file name field in both the WT_FH and WT_FILE_HANDLE 102 * structures, which isn't ideal. There would be compromises to keeping 103 * a single copy: If it were in WT_FH, file systems could not access 104 * the name field, if it were just in the WT_FILE_HANDLE internal 105 * WiredTiger code would need to maintain a string inside a structure 106 * that is owned by the user (since we care about the content of the 107 * file name). Keeping two copies seems most reasonable. 108 */ 109 const char *name; /* File name */ 110 111 uint64_t name_hash; /* hash of name */ 112 TAILQ_ENTRY(__wt_fh) q; /* internal queue */ 113 TAILQ_ENTRY(__wt_fh) hashq; /* internal hash queue */ 114 u_int ref; /* reference count */ 115 116 WT_FILE_HANDLE *handle; 117 }; 118 119 #ifdef _WIN32 120 struct __wt_file_handle_win { 121 WT_FILE_HANDLE iface; 122 123 /* 124 * Windows specific file handle fields 125 */ 126 HANDLE filehandle; /* Windows file handle */ 127 HANDLE filehandle_secondary; /* Windows file handle 128 for file size changes */ 129 bool direct_io; /* O_DIRECT configured */ 130 }; 131 132 #else 133 134 struct __wt_file_handle_posix { 135 WT_FILE_HANDLE iface; 136 137 /* 138 * POSIX specific file handle fields 139 */ 140 int fd; /* POSIX file handle */ 141 142 bool direct_io; /* O_DIRECT configured */ 143 }; 144 #endif 145 146 struct __wt_file_handle_inmem { 147 WT_FILE_HANDLE iface; 148 149 /* 150 * In memory specific file handle fields 151 */ 152 uint64_t name_hash; /* hash of name */ 153 TAILQ_ENTRY(__wt_file_handle_inmem) q; /* internal queue, hash queue */ 154 TAILQ_ENTRY(__wt_file_handle_inmem) hashq; 155 156 WT_ITEM buf; /* Data */ 157 u_int ref; /* Reference count */ 158 }; 159 160 struct __wt_fstream { 161 const char *name; /* Stream name */ 162 163 FILE *fp; /* stdio FILE stream */ 164 WT_FH *fh; /* WT file handle */ 165 wt_off_t off; /* Read/write offset */ 166 wt_off_t size; /* File size */ 167 WT_ITEM buf; /* Data */ 168 169 /* AUTOMATIC FLAG VALUE GENERATION START */ 170 #define WT_STREAM_APPEND 0x1u /* Open a stream for append */ 171 #define WT_STREAM_READ 0x2u /* Open a stream for read */ 172 #define WT_STREAM_WRITE 0x4u /* Open a stream for write */ 173 /* AUTOMATIC FLAG VALUE GENERATION STOP */ 174 uint32_t flags; 175 176 int (*close)(WT_SESSION_IMPL *, WT_FSTREAM *); 177 int (*fstr_flush)(WT_SESSION_IMPL *, WT_FSTREAM *); 178 int (*fstr_getline)(WT_SESSION_IMPL *, WT_FSTREAM *, WT_ITEM *); 179 int (*fstr_printf)( 180 WT_SESSION_IMPL *, WT_FSTREAM *, const char *, va_list); 181 }; 182