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