diff options
author | Luke Chen <luke.chen@mongodb.com> | 2019-08-21 05:23:37 +0000 |
---|---|---|
committer | evergreen <evergreen@mongodb.com> | 2019-08-21 05:23:37 +0000 |
commit | ac41c65f6355f83aac70136324c98561ac79daa1 (patch) | |
tree | a7c3f7ef090b59c6a06838a02c96bd1d49e1c729 /src/third_party/wiredtiger/src/os_common/os_fhandle.c | |
parent | f54709196711c63a429b71f47c584661286d675f (diff) | |
download | mongo-ac41c65f6355f83aac70136324c98561ac79daa1.tar.gz |
Import wiredtiger: 7dfd9391862bc9a6d84868c4dc51689c45a3aacf from branch mongodb-4.4
ref: c809757d8b..7dfd939186
for: 4.3.1
WT-4658 Apply Clang Format
WT-4810 Adding WT_ERR_ASSERT and WT_RET_ASSERT macros
WT-5046 Prepared transactions aren't properly cleared from global table with WT_CONN_LOG_DEBUG_MODE enabled
Diffstat (limited to 'src/third_party/wiredtiger/src/os_common/os_fhandle.c')
-rw-r--r-- | src/third_party/wiredtiger/src/os_common/os_fhandle.c | 839 |
1 files changed, 412 insertions, 427 deletions
diff --git a/src/third_party/wiredtiger/src/os_common/os_fhandle.c b/src/third_party/wiredtiger/src/os_common/os_fhandle.c index 387aa0d4aa3..bba63e2ae44 100644 --- a/src/third_party/wiredtiger/src/os_common/os_fhandle.c +++ b/src/third_party/wiredtiger/src/os_common/os_fhandle.c @@ -10,542 +10,527 @@ /* * __fhandle_method_finalize -- - * Initialize any NULL WT_FH structure methods to not-supported. Doing - * this means that custom file systems with incomplete implementations - * won't dereference NULL pointers. + * Initialize any NULL WT_FH structure methods to not-supported. Doing this means that custom + * file systems with incomplete implementations won't dereference NULL pointers. */ static int -__fhandle_method_finalize( - WT_SESSION_IMPL *session, WT_FILE_HANDLE *handle, bool readonly) +__fhandle_method_finalize(WT_SESSION_IMPL *session, WT_FILE_HANDLE *handle, bool readonly) { -#define WT_HANDLE_METHOD_REQ(name) \ - if (handle->name == NULL) \ - WT_RET_MSG(session, EINVAL, \ - "a WT_FILE_HANDLE.%s method must be configured", #name) - - WT_HANDLE_METHOD_REQ(close); - /* not required: fh_advise */ - /* not required: fh_extend */ - /* not required: fh_extend_nolock */ - WT_HANDLE_METHOD_REQ(fh_lock); - /* not required: fh_map */ - /* not required: fh_map_discard */ - /* not required: fh_map_preload */ - /* not required: fh_unmap */ - WT_HANDLE_METHOD_REQ(fh_read); - WT_HANDLE_METHOD_REQ(fh_size); - if (!readonly) - WT_HANDLE_METHOD_REQ(fh_sync); - /* not required: fh_sync_nowait */ - /* not required: fh_truncate */ - if (!readonly) - WT_HANDLE_METHOD_REQ(fh_write); - - return (0); +#define WT_HANDLE_METHOD_REQ(name) \ + if (handle->name == NULL) \ + WT_RET_MSG(session, EINVAL, "a WT_FILE_HANDLE.%s method must be configured", #name) + + WT_HANDLE_METHOD_REQ(close); + /* not required: fh_advise */ + /* not required: fh_extend */ + /* not required: fh_extend_nolock */ + WT_HANDLE_METHOD_REQ(fh_lock); + /* not required: fh_map */ + /* not required: fh_map_discard */ + /* not required: fh_map_preload */ + /* not required: fh_unmap */ + WT_HANDLE_METHOD_REQ(fh_read); + WT_HANDLE_METHOD_REQ(fh_size); + if (!readonly) + WT_HANDLE_METHOD_REQ(fh_sync); + /* not required: fh_sync_nowait */ + /* not required: fh_truncate */ + if (!readonly) + WT_HANDLE_METHOD_REQ(fh_write); + + return (0); } #ifdef HAVE_DIAGNOSTIC /* * __wt_handle_is_open -- - * Return if there's an open handle matching a name. + * Return if there's an open handle matching a name. */ bool __wt_handle_is_open(WT_SESSION_IMPL *session, const char *name) { - WT_CONNECTION_IMPL *conn; - WT_FH *fh; - uint64_t bucket, hash; - bool found; + WT_CONNECTION_IMPL *conn; + WT_FH *fh; + uint64_t bucket, hash; + bool found; - conn = S2C(session); - found = false; + conn = S2C(session); + found = false; - hash = __wt_hash_city64(name, strlen(name)); - bucket = hash % WT_HASH_ARRAY_SIZE; + hash = __wt_hash_city64(name, strlen(name)); + bucket = hash % WT_HASH_ARRAY_SIZE; - __wt_spin_lock(session, &conn->fh_lock); + __wt_spin_lock(session, &conn->fh_lock); - TAILQ_FOREACH(fh, &conn->fhhash[bucket], hashq) - if (strcmp(name, fh->name) == 0) { - found = true; - break; - } + TAILQ_FOREACH (fh, &conn->fhhash[bucket], hashq) + if (strcmp(name, fh->name) == 0) { + found = true; + break; + } - __wt_spin_unlock(session, &conn->fh_lock); + __wt_spin_unlock(session, &conn->fh_lock); - return (found); + return (found); } #endif /* * __handle_search -- - * Search for a matching handle. + * Search for a matching handle. */ static bool -__handle_search( - WT_SESSION_IMPL *session, const char *name, WT_FH *newfh, WT_FH **fhp) +__handle_search(WT_SESSION_IMPL *session, const char *name, WT_FH *newfh, WT_FH **fhp) { - WT_CONNECTION_IMPL *conn; - WT_FH *fh; - uint64_t bucket, hash; - bool found; - - *fhp = NULL; - - conn = S2C(session); - found = false; - - hash = __wt_hash_city64(name, strlen(name)); - bucket = hash % WT_HASH_ARRAY_SIZE; - - __wt_spin_lock(session, &conn->fh_lock); - - /* - * If we already have the file open, increment the reference count and - * return a pointer. - */ - TAILQ_FOREACH(fh, &conn->fhhash[bucket], hashq) - if (strcmp(name, fh->name) == 0) { - ++fh->ref; - *fhp = fh; - found = true; - break; - } - - /* If we don't find a match, optionally add a new entry. */ - if (!found && newfh != NULL) { - newfh->name_hash = hash; - WT_FILE_HANDLE_INSERT(conn, newfh, bucket); - (void)__wt_atomic_add32(&conn->open_file_count, 1); - - ++newfh->ref; - *fhp = newfh; - } - - __wt_spin_unlock(session, &conn->fh_lock); - - return (found); + WT_CONNECTION_IMPL *conn; + WT_FH *fh; + uint64_t bucket, hash; + bool found; + + *fhp = NULL; + + conn = S2C(session); + found = false; + + hash = __wt_hash_city64(name, strlen(name)); + bucket = hash % WT_HASH_ARRAY_SIZE; + + __wt_spin_lock(session, &conn->fh_lock); + + /* + * If we already have the file open, increment the reference count and return a pointer. + */ + TAILQ_FOREACH (fh, &conn->fhhash[bucket], hashq) + if (strcmp(name, fh->name) == 0) { + ++fh->ref; + *fhp = fh; + found = true; + break; + } + + /* If we don't find a match, optionally add a new entry. */ + if (!found && newfh != NULL) { + newfh->name_hash = hash; + WT_FILE_HANDLE_INSERT(conn, newfh, bucket); + (void)__wt_atomic_add32(&conn->open_file_count, 1); + + ++newfh->ref; + *fhp = newfh; + } + + __wt_spin_unlock(session, &conn->fh_lock); + + return (found); } /* * __open_verbose_file_type_tag -- - * Return a string describing a file type. + * Return a string describing a file type. */ static const char * __open_verbose_file_type_tag(WT_FS_OPEN_FILE_TYPE file_type) { - /* - * WT_FS_OPEN_FILE_TYPE is an enum and the switch exhaustively lists the - * cases, but clang, lint and gcc argue over whether or not the switch - * is exhaustive, or if a temporary variable inserted into the mix is - * set but never read. Break out of the switch, returning some value in - * all cases, just to shut everybody up. - */ - switch (file_type) { - case WT_FS_OPEN_FILE_TYPE_CHECKPOINT: - return ("checkpoint"); - case WT_FS_OPEN_FILE_TYPE_DATA: - return ("data"); - case WT_FS_OPEN_FILE_TYPE_DIRECTORY: - return ("directory"); - case WT_FS_OPEN_FILE_TYPE_LOG: - return ("log"); - case WT_FS_OPEN_FILE_TYPE_REGULAR: - break; - } - return ("regular"); + /* + * WT_FS_OPEN_FILE_TYPE is an enum and the switch exhaustively lists the cases, but clang, lint + * and gcc argue over whether or not the switch is exhaustive, or if a temporary variable + * inserted into the mix is set but never read. Break out of the switch, returning some value in + * all cases, just to shut everybody up. + */ + switch (file_type) { + case WT_FS_OPEN_FILE_TYPE_CHECKPOINT: + return ("checkpoint"); + case WT_FS_OPEN_FILE_TYPE_DATA: + return ("data"); + case WT_FS_OPEN_FILE_TYPE_DIRECTORY: + return ("directory"); + case WT_FS_OPEN_FILE_TYPE_LOG: + return ("log"); + case WT_FS_OPEN_FILE_TYPE_REGULAR: + break; + } + return ("regular"); } /* * __open_verbose -- - * Optionally output a verbose message on handle open. + * Optionally output a verbose message on handle open. */ static inline int -__open_verbose(WT_SESSION_IMPL *session, - const char *name, WT_FS_OPEN_FILE_TYPE file_type, u_int flags) +__open_verbose( + WT_SESSION_IMPL *session, const char *name, WT_FS_OPEN_FILE_TYPE file_type, u_int flags) { - WT_DECL_ITEM(tmp); - WT_DECL_RET; - const char *sep; - - if (!WT_VERBOSE_ISSET(session, WT_VERB_FILEOPS)) - return (0); - - /* - * It's useful to track file opens when debugging platforms, take some - * effort to output good tracking information. - */ - WT_RET(__wt_scr_alloc(session, 0, &tmp)); - sep = " ("; -#define WT_FS_OPEN_VERBOSE_FLAG(f, name) \ - if (LF_ISSET(f)) { \ - WT_ERR(__wt_buf_catfmt( \ - session, tmp, "%s%s", sep, name)); \ - sep = ", "; \ - } - - WT_FS_OPEN_VERBOSE_FLAG(WT_FS_OPEN_CREATE, "create"); - WT_FS_OPEN_VERBOSE_FLAG(WT_FS_OPEN_DIRECTIO, "direct-IO"); - WT_FS_OPEN_VERBOSE_FLAG(WT_FS_OPEN_EXCLUSIVE, "exclusive"); - WT_FS_OPEN_VERBOSE_FLAG(WT_FS_OPEN_FIXED, "fixed"); - WT_FS_OPEN_VERBOSE_FLAG(WT_FS_OPEN_READONLY, "readonly"); - - if (tmp->size != 0) - WT_ERR(__wt_buf_catfmt(session, tmp, ")")); - - __wt_verbose(session, WT_VERB_FILEOPS, - "%s: file-open: type %s%s", - name, __open_verbose_file_type_tag(file_type), - tmp->size == 0 ? "" : (char *)tmp->data); - -err: __wt_scr_free(session, &tmp); - return (ret); + WT_DECL_ITEM(tmp); + WT_DECL_RET; + const char *sep; + + if (!WT_VERBOSE_ISSET(session, WT_VERB_FILEOPS)) + return (0); + + /* + * It's useful to track file opens when debugging platforms, take some effort to output good + * tracking information. + */ + WT_RET(__wt_scr_alloc(session, 0, &tmp)); + sep = " ("; +#define WT_FS_OPEN_VERBOSE_FLAG(f, name) \ + if (LF_ISSET(f)) { \ + WT_ERR(__wt_buf_catfmt(session, tmp, "%s%s", sep, name)); \ + sep = ", "; \ + } + + WT_FS_OPEN_VERBOSE_FLAG(WT_FS_OPEN_CREATE, "create"); + WT_FS_OPEN_VERBOSE_FLAG(WT_FS_OPEN_DIRECTIO, "direct-IO"); + WT_FS_OPEN_VERBOSE_FLAG(WT_FS_OPEN_EXCLUSIVE, "exclusive"); + WT_FS_OPEN_VERBOSE_FLAG(WT_FS_OPEN_FIXED, "fixed"); + WT_FS_OPEN_VERBOSE_FLAG(WT_FS_OPEN_READONLY, "readonly"); + + if (tmp->size != 0) + WT_ERR(__wt_buf_catfmt(session, tmp, ")")); + + __wt_verbose(session, WT_VERB_FILEOPS, "%s: file-open: type %s%s", name, + __open_verbose_file_type_tag(file_type), tmp->size == 0 ? "" : (char *)tmp->data); + +err: + __wt_scr_free(session, &tmp); + return (ret); } /* * __wt_open -- - * Open a file handle. + * Open a file handle. */ int -__wt_open(WT_SESSION_IMPL *session, - const char *name, WT_FS_OPEN_FILE_TYPE file_type, u_int flags, WT_FH **fhp) +__wt_open(WT_SESSION_IMPL *session, const char *name, WT_FS_OPEN_FILE_TYPE file_type, u_int flags, + WT_FH **fhp) { - WT_CONNECTION_IMPL *conn; - WT_DECL_RET; - WT_FH *fh; - WT_FILE_SYSTEM *file_system; - char *path; - bool lock_file, open_called; - - WT_ASSERT(session, file_type != 0); /* A file type is required. */ - - *fhp = NULL; - - conn = S2C(session); - file_system = conn->file_system; - fh = NULL; - open_called = false; - path = NULL; - - WT_RET(__open_verbose(session, name, file_type, flags)); - - /* Check if the handle is already open. */ - if (__handle_search(session, name, NULL, &fh)) { - *fhp = fh; - return (0); - } - - /* Allocate and initialize the handle. */ - WT_ERR(__wt_calloc_one(session, &fh)); - WT_ERR(__wt_strdup(session, name, &fh->name)); - - fh->file_type = file_type; - - /* - * If this is a read-only connection, open all files read-only except - * the lock file. - * - * The only file created in read-only mode is the lock file. - */ - if (F_ISSET(conn, WT_CONN_READONLY)) { - lock_file = strcmp(name, WT_SINGLETHREAD) == 0; - if (!lock_file) - LF_SET(WT_FS_OPEN_READONLY); - WT_ASSERT(session, lock_file || !LF_ISSET(WT_FS_OPEN_CREATE)); - } - - /* Create the path to the file. */ - if (!LF_ISSET(WT_FS_OPEN_FIXED)) - WT_ERR(__wt_filename(session, name, &path)); - - /* Call the underlying open function. */ - WT_ERR(file_system->fs_open_file(file_system, &session->iface, - path == NULL ? name : path, file_type, flags, &fh->handle)); - open_called = true; - - WT_ERR(__fhandle_method_finalize( - session, fh->handle, LF_ISSET(WT_FS_OPEN_READONLY))); - - /* - * Repeat the check for a match: if there's no match, link our newly - * created handle onto the database's list of files. - */ - if (__handle_search(session, name, fh, fhp)) { -err: if (open_called) - WT_TRET(fh->handle->close( - fh->handle, (WT_SESSION *)session)); - if (fh != NULL) { - __wt_free(session, fh->name); - __wt_free(session, fh); - } - } - - __wt_free(session, path); - return (ret); + WT_CONNECTION_IMPL *conn; + WT_DECL_RET; + WT_FH *fh; + WT_FILE_SYSTEM *file_system; + char *path; + bool lock_file, open_called; + + WT_ASSERT(session, file_type != 0); /* A file type is required. */ + + *fhp = NULL; + + conn = S2C(session); + file_system = conn->file_system; + fh = NULL; + open_called = false; + path = NULL; + + WT_RET(__open_verbose(session, name, file_type, flags)); + + /* Check if the handle is already open. */ + if (__handle_search(session, name, NULL, &fh)) { + *fhp = fh; + return (0); + } + + /* Allocate and initialize the handle. */ + WT_ERR(__wt_calloc_one(session, &fh)); + WT_ERR(__wt_strdup(session, name, &fh->name)); + + fh->file_type = file_type; + + /* + * If this is a read-only connection, open all files read-only except + * the lock file. + * + * The only file created in read-only mode is the lock file. + */ + if (F_ISSET(conn, WT_CONN_READONLY)) { + lock_file = strcmp(name, WT_SINGLETHREAD) == 0; + if (!lock_file) + LF_SET(WT_FS_OPEN_READONLY); + WT_ASSERT(session, lock_file || !LF_ISSET(WT_FS_OPEN_CREATE)); + } + + /* Create the path to the file. */ + if (!LF_ISSET(WT_FS_OPEN_FIXED)) + WT_ERR(__wt_filename(session, name, &path)); + + /* Call the underlying open function. */ + WT_ERR(file_system->fs_open_file( + file_system, &session->iface, path == NULL ? name : path, file_type, flags, &fh->handle)); + open_called = true; + + WT_ERR(__fhandle_method_finalize(session, fh->handle, LF_ISSET(WT_FS_OPEN_READONLY))); + + /* + * Repeat the check for a match: if there's no match, link our newly created handle onto the + * database's list of files. + */ + if (__handle_search(session, name, fh, fhp)) { +err: + if (open_called) + WT_TRET(fh->handle->close(fh->handle, (WT_SESSION *)session)); + if (fh != NULL) { + __wt_free(session, fh->name); + __wt_free(session, fh); + } + } + + __wt_free(session, path); + return (ret); } /* * __handle_close -- - * Final close of a handle. + * Final close of a handle. */ static int __handle_close(WT_SESSION_IMPL *session, WT_FH *fh, bool locked) { - WT_CONNECTION_IMPL *conn; - WT_DECL_RET; - uint64_t bucket; + WT_CONNECTION_IMPL *conn; + WT_DECL_RET; + uint64_t bucket; - conn = S2C(session); + conn = S2C(session); - if (fh->ref != 0) { - __wt_errx(session, - "Closing a file handle with open references: %s", fh->name); - } + if (fh->ref != 0) { + __wt_errx(session, "Closing a file handle with open references: %s", fh->name); + } - /* Remove from the list. */ - bucket = fh->name_hash % WT_HASH_ARRAY_SIZE; - WT_FILE_HANDLE_REMOVE(conn, fh, bucket); - (void)__wt_atomic_sub32(&conn->open_file_count, 1); + /* Remove from the list. */ + bucket = fh->name_hash % WT_HASH_ARRAY_SIZE; + WT_FILE_HANDLE_REMOVE(conn, fh, bucket); + (void)__wt_atomic_sub32(&conn->open_file_count, 1); - if (locked) - __wt_spin_unlock(session, &conn->fh_lock); + if (locked) + __wt_spin_unlock(session, &conn->fh_lock); - /* Discard underlying resources. */ - WT_TRET(fh->handle->close(fh->handle, (WT_SESSION *)session)); + /* Discard underlying resources. */ + WT_TRET(fh->handle->close(fh->handle, (WT_SESSION *)session)); - __wt_free(session, fh->name); - __wt_free(session, fh); + __wt_free(session, fh->name); + __wt_free(session, fh); - return (ret); + return (ret); } /* * __wt_close -- - * Close a file handle. + * Close a file handle. */ int __wt_close(WT_SESSION_IMPL *session, WT_FH **fhp) { - WT_CONNECTION_IMPL *conn; - WT_FH *fh; - - conn = S2C(session); - - if (*fhp == NULL) - return (0); - fh = *fhp; - *fhp = NULL; - - /* Track handle-close as a file operation, so open and close match. */ - __wt_verbose(session, WT_VERB_FILEOPS, "%s: file-close", fh->name); - - /* - * If the reference count hasn't gone to 0, or if it's an in-memory - * object, we're done. - * - * Assert the reference count is correct, but don't let it wrap. - */ - __wt_spin_lock(session, &conn->fh_lock); - WT_ASSERT(session, fh->ref > 0); - if ((fh->ref > 0 && --fh->ref > 0)) { - __wt_spin_unlock(session, &conn->fh_lock); - return (0); - } - - return (__handle_close(session, fh, true)); + WT_CONNECTION_IMPL *conn; + WT_FH *fh; + + conn = S2C(session); + + if (*fhp == NULL) + return (0); + fh = *fhp; + *fhp = NULL; + + /* Track handle-close as a file operation, so open and close match. */ + __wt_verbose(session, WT_VERB_FILEOPS, "%s: file-close", fh->name); + + /* + * If the reference count hasn't gone to 0, or if it's an in-memory + * object, we're done. + * + * Assert the reference count is correct, but don't let it wrap. + */ + __wt_spin_lock(session, &conn->fh_lock); + WT_ASSERT(session, fh->ref > 0); + if ((fh->ref > 0 && --fh->ref > 0)) { + __wt_spin_unlock(session, &conn->fh_lock); + return (0); + } + + return (__handle_close(session, fh, true)); } /* * __wt_fsync_background_chk -- - * Return if background fsync is supported. + * Return if background fsync is supported. */ bool __wt_fsync_background_chk(WT_SESSION_IMPL *session) { - WT_CONNECTION_IMPL *conn; - WT_FH *fh; - WT_FILE_HANDLE *handle; - bool supported; - - conn = S2C(session); - supported = true; - __wt_spin_lock(session, &conn->fh_lock); - /* - * Look for the first data file handle and see if - * the fsync nowait function is supported. - */ - TAILQ_FOREACH(fh, &conn->fhqh, q) { - handle = fh->handle; - if (fh->file_type != WT_FS_OPEN_FILE_TYPE_DATA) - continue; - /* - * If we don't have a function, return false, otherwise - * return true. In any case, we are done with the loop. - */ - if (handle->fh_sync_nowait == NULL) - supported = false; - break; - } - __wt_spin_unlock(session, &conn->fh_lock); - return (supported); + WT_CONNECTION_IMPL *conn; + WT_FH *fh; + WT_FILE_HANDLE *handle; + bool supported; + + conn = S2C(session); + supported = true; + __wt_spin_lock(session, &conn->fh_lock); + /* + * Look for the first data file handle and see if the fsync nowait function is supported. + */ + TAILQ_FOREACH (fh, &conn->fhqh, q) { + handle = fh->handle; + if (fh->file_type != WT_FS_OPEN_FILE_TYPE_DATA) + continue; + /* + * If we don't have a function, return false, otherwise return true. In any case, we are + * done with the loop. + */ + if (handle->fh_sync_nowait == NULL) + supported = false; + break; + } + __wt_spin_unlock(session, &conn->fh_lock); + return (supported); } /* * __fsync_background -- - * Background fsync for a single dirty file handle. + * Background fsync for a single dirty file handle. */ static int __fsync_background(WT_SESSION_IMPL *session, WT_FH *fh) { - WT_CONNECTION_IMPL *conn; - WT_DECL_RET; - WT_FILE_HANDLE *handle; - uint64_t now; - - conn = S2C(session); - WT_STAT_CONN_INCR(session, fsync_all_fh_total); - - handle = fh->handle; - if (handle->fh_sync_nowait == NULL || - fh->written < WT_CAPACITY_FILE_THRESHOLD) - return (0); - - /* Only sync data files. */ - if (fh->file_type != WT_FS_OPEN_FILE_TYPE_DATA) - return (0); - - now = __wt_clock(session); - if (fh->last_sync == 0 || WT_CLOCKDIFF_SEC(now, fh->last_sync) > 0) { - __wt_spin_unlock(session, &conn->fh_lock); - - /* - * We set the false flag to indicate a non-blocking background - * fsync, but there is no guarantee that it doesn't block. If - * we wanted to detect if it is blocking, adding a clock call - * and checking the time would be done here. - */ - ret = __wt_fsync(session, fh, false); - if (ret == 0) { - WT_STAT_CONN_INCR(session, fsync_all_fh); - fh->last_sync = now; - fh->written = 0; - } - - __wt_spin_lock(session, &conn->fh_lock); - } - return (ret); + WT_CONNECTION_IMPL *conn; + WT_DECL_RET; + WT_FILE_HANDLE *handle; + uint64_t now; + + conn = S2C(session); + WT_STAT_CONN_INCR(session, fsync_all_fh_total); + + handle = fh->handle; + if (handle->fh_sync_nowait == NULL || fh->written < WT_CAPACITY_FILE_THRESHOLD) + return (0); + + /* Only sync data files. */ + if (fh->file_type != WT_FS_OPEN_FILE_TYPE_DATA) + return (0); + + now = __wt_clock(session); + if (fh->last_sync == 0 || WT_CLOCKDIFF_SEC(now, fh->last_sync) > 0) { + __wt_spin_unlock(session, &conn->fh_lock); + + /* + * We set the false flag to indicate a non-blocking background fsync, but there is no + * guarantee that it doesn't block. If we wanted to detect if it is blocking, adding a clock + * call and checking the time would be done here. + */ + ret = __wt_fsync(session, fh, false); + if (ret == 0) { + WT_STAT_CONN_INCR(session, fsync_all_fh); + fh->last_sync = now; + fh->written = 0; + } + + __wt_spin_lock(session, &conn->fh_lock); + } + return (ret); } /* * __wt_fsync_background -- - * Background fsync for all dirty file handles. + * Background fsync for all dirty file handles. */ int __wt_fsync_background(WT_SESSION_IMPL *session) { - WT_CONNECTION_IMPL *conn; - WT_DECL_RET; - WT_FH *fh, *fhnext; - - conn = S2C(session); - __wt_spin_lock(session, &conn->fh_lock); - TAILQ_FOREACH_SAFE(fh, &conn->fhqh, q, fhnext) { - /* - * The worker routine will unlock the list to avoid holding it - * locked over an fsync. Increment the count on the current and - * next handles to guarantee their validity. - */ - if (fhnext != NULL) - ++fhnext->ref; - ++fh->ref; - - WT_TRET(__fsync_background(session, fh)); - - /* - * The file handle reference may have gone to 0, in which case - * we're responsible for the close. Configure the close routine - * to drop the lock, which means we must re-acquire it. - */ - if (--fh->ref == 0) { - WT_TRET(__handle_close(session, fh, true)); - __wt_spin_lock(session, &conn->fh_lock); - } - - /* - * Decrement the next element's reference count. It might have - * gone to 0 as well, in which case we'll close it in the next - * loop iteration. - */ - if (fhnext != NULL) - --fhnext->ref; - } - __wt_spin_unlock(session, &conn->fh_lock); - return (ret); + WT_CONNECTION_IMPL *conn; + WT_DECL_RET; + WT_FH *fh, *fhnext; + + conn = S2C(session); + __wt_spin_lock(session, &conn->fh_lock); + TAILQ_FOREACH_SAFE(fh, &conn->fhqh, q, fhnext) + { + /* + * The worker routine will unlock the list to avoid holding it locked over an fsync. + * Increment the count on the current and next handles to guarantee their validity. + */ + if (fhnext != NULL) + ++fhnext->ref; + ++fh->ref; + + WT_TRET(__fsync_background(session, fh)); + + /* + * The file handle reference may have gone to 0, in which case we're responsible for the + * close. Configure the close routine to drop the lock, which means we must re-acquire it. + */ + if (--fh->ref == 0) { + WT_TRET(__handle_close(session, fh, true)); + __wt_spin_lock(session, &conn->fh_lock); + } + + /* + * Decrement the next element's reference count. It might have gone to 0 as well, in which + * case we'll close it in the next loop iteration. + */ + if (fhnext != NULL) + --fhnext->ref; + } + __wt_spin_unlock(session, &conn->fh_lock); + return (ret); } /* * __wt_close_connection_close -- - * Close any open file handles at connection close. + * Close any open file handles at connection close. */ int __wt_close_connection_close(WT_SESSION_IMPL *session) { - WT_DECL_RET; - WT_FH *fh, *fh_tmp; - - WT_TAILQ_SAFE_REMOVE_BEGIN(fh, &S2C(session)->fhqh, q, fh_tmp) { - WT_TRET(__handle_close(session, fh, false)); - } WT_TAILQ_SAFE_REMOVE_END - return (ret); + WT_DECL_RET; + WT_FH *fh, *fh_tmp; + + WT_TAILQ_SAFE_REMOVE_BEGIN(fh, &S2C(session)->fhqh, q, fh_tmp) + { + WT_TRET(__handle_close(session, fh, false)); + } + WT_TAILQ_SAFE_REMOVE_END + return (ret); } /* * __wt_file_zero -- - * Zero out the file from offset for size bytes. + * Zero out the file from offset for size bytes. */ int -__wt_file_zero(WT_SESSION_IMPL *session, - WT_FH *fh, wt_off_t start_off, wt_off_t size) +__wt_file_zero(WT_SESSION_IMPL *session, WT_FH *fh, wt_off_t start_off, wt_off_t size) { - WT_DECL_ITEM(zerobuf); - WT_DECL_RET; - WT_THROTTLE_TYPE type; - uint64_t bufsz, off, partial, wrlen; - - zerobuf = NULL; - bufsz = WT_MIN((uint64_t)size, WT_MEGABYTE); - /* - * For now logging is the only type and statistic. This needs - * updating if block manager decides to use this function. - */ - type = WT_THROTTLE_LOG; - WT_STAT_CONN_INCR(session, log_zero_fills); - WT_RET(__wt_scr_alloc(session, bufsz, &zerobuf)); - memset(zerobuf->mem, 0, zerobuf->memsize); - off = (uint64_t)start_off; - while (off < (uint64_t)size) { - /* - * We benefit from aligning our writes when we can. Log files - * will typically want to start to zero after the log header - * and the bufsz is a sector-aligned size. So align when - * we can. - */ - partial = off % bufsz; - if (partial != 0) - wrlen = bufsz - partial; - else - wrlen = bufsz; - /* - * Check if we're writing a partial amount at the end too. - */ - if ((uint64_t)size - off < bufsz) - wrlen = (uint64_t)size - off; - __wt_capacity_throttle(session, wrlen, type); - WT_ERR(__wt_write(session, - fh, (wt_off_t)off, (size_t)wrlen, zerobuf->mem)); - off += wrlen; - } -err: __wt_scr_free(session, &zerobuf); - return (ret); + WT_DECL_ITEM(zerobuf); + WT_DECL_RET; + WT_THROTTLE_TYPE type; + uint64_t bufsz, off, partial, wrlen; + + zerobuf = NULL; + bufsz = WT_MIN((uint64_t)size, WT_MEGABYTE); + /* + * For now logging is the only type and statistic. This needs updating if block manager decides + * to use this function. + */ + type = WT_THROTTLE_LOG; + WT_STAT_CONN_INCR(session, log_zero_fills); + WT_RET(__wt_scr_alloc(session, bufsz, &zerobuf)); + memset(zerobuf->mem, 0, zerobuf->memsize); + off = (uint64_t)start_off; + while (off < (uint64_t)size) { + /* + * We benefit from aligning our writes when we can. Log files will typically want to start + * to zero after the log header and the bufsz is a sector-aligned size. So align when we + * can. + */ + partial = off % bufsz; + if (partial != 0) + wrlen = bufsz - partial; + else + wrlen = bufsz; + /* + * Check if we're writing a partial amount at the end too. + */ + if ((uint64_t)size - off < bufsz) + wrlen = (uint64_t)size - off; + __wt_capacity_throttle(session, wrlen, type); + WT_ERR(__wt_write(session, fh, (wt_off_t)off, (size_t)wrlen, zerobuf->mem)); + off += wrlen; + } +err: + __wt_scr_free(session, &zerobuf); + return (ret); } |