Compare commits
90 Commits
mongodb-3.
...
mongodb-3.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dddca65606 | ||
|
|
2969c02ab9 | ||
|
|
82323cf72f | ||
|
|
859c8eda1e | ||
|
|
24cd107c1d | ||
|
|
3dc8860451 | ||
|
|
9383fc98ee | ||
|
|
307e63aac7 | ||
|
|
6f81f19793 | ||
|
|
848e5f5c0b | ||
|
|
8b7110bfac | ||
|
|
f4954f6592 | ||
|
|
dd2a33849a | ||
|
|
a63e21b838 | ||
|
|
30e49acc90 | ||
|
|
063dbdfe45 | ||
|
|
9ee39b8aea | ||
|
|
d68800d0e9 | ||
|
|
ded2149b2c | ||
|
|
0f36f40c37 | ||
|
|
a6a64e986b | ||
|
|
234b68b116 | ||
|
|
5d215904c3 | ||
|
|
18879587af | ||
|
|
6bfcb1ca5b | ||
|
|
71c0588a77 | ||
|
|
58765850aa | ||
|
|
30d327f810 | ||
|
|
88b898e7cb | ||
|
|
7ea2631de2 | ||
|
|
039fe06082 | ||
|
|
43e885a0f9 | ||
|
|
5cdd3e320c | ||
|
|
563b7823f7 | ||
|
|
5e3a56f0ab | ||
|
|
bc929dbcf1 | ||
|
|
07966a492a | ||
|
|
67e412d4c5 | ||
|
|
3c2ad56b50 | ||
|
|
b1768d0d9f | ||
|
|
2893117baa | ||
|
|
4380cec93d | ||
|
|
21b5f9951e | ||
|
|
decd9166cc | ||
|
|
d835a0c0a8 | ||
|
|
48e1343e40 | ||
|
|
eb838c7f12 | ||
|
|
a6957512a4 | ||
|
|
197eef00fd | ||
|
|
7a4f3259b4 | ||
|
|
8326df6b76 | ||
|
|
b65381f64c | ||
|
|
0019262fed | ||
|
|
4d72349b8a | ||
|
|
4898aa408f | ||
|
|
9d375e3416 | ||
|
|
d9ec1ff8ec | ||
|
|
465dca8b46 | ||
|
|
f95877af13 | ||
|
|
62c1a7aa36 | ||
|
|
0dc3f20df6 | ||
|
|
0537648e03 | ||
|
|
3c856645c8 | ||
|
|
10208e8284 | ||
|
|
16e3e48d98 | ||
|
|
5205bb1f0f | ||
|
|
dca63120b7 | ||
|
|
0cccab30c0 | ||
|
|
578a856c19 | ||
|
|
a85c5cda41 | ||
|
|
6da2dc175b | ||
|
|
7ffa315e39 | ||
|
|
26d1ad271f | ||
|
|
fdedd3621c | ||
|
|
4187f419f8 | ||
|
|
42823c9682 | ||
|
|
fbaf1cf4f5 | ||
|
|
3d845c98cb | ||
|
|
1d2fe8a145 | ||
|
|
bdaaaec87d | ||
|
|
35cc116acd | ||
|
|
cbe0fad3e9 | ||
|
|
4f9aa1c548 | ||
|
|
1f44c05f91 | ||
|
|
e31aa8cf29 | ||
|
|
c90bc747e1 | ||
|
|
2c1b7aa80b | ||
|
|
41762ae13c | ||
|
|
f7691f63a6 | ||
|
|
9be5497753 |
@@ -129,7 +129,8 @@ cycle_idle_tables(void *arg)
|
||||
* Drop the table. Keep retrying on EBUSY failure - it is an
|
||||
* expected return when checkpoints are happening.
|
||||
*/
|
||||
while ((ret = session->drop(session, uri, "force")) == EBUSY)
|
||||
while ((ret = session->drop(
|
||||
session, uri, "force,checkpoint_wait=false")) == EBUSY)
|
||||
__wt_sleep(1, 0);
|
||||
|
||||
if (ret != 0 && ret != EBUSY) {
|
||||
|
||||
20
bench/wtperf/runners/checkpoint_schema_race.wtperf
Normal file
20
bench/wtperf/runners/checkpoint_schema_race.wtperf
Normal file
@@ -0,0 +1,20 @@
|
||||
# Check create and drop behavior concurrent with checkpoints (WT-2798).
|
||||
# Setup a multiple tables and a cache size large enough that checkpoints can
|
||||
# take a long time.
|
||||
conn_config="cache_size=8GB,log=(enabled=false),checkpoint=(wait=30)"
|
||||
table_config="leaf_page_max=4k,internal_page_max=16k,type=file"
|
||||
icount=10000000
|
||||
table_count=100
|
||||
table_count_idle=100
|
||||
# Turn on create/drop of idle tables, but don't worry if individual operations
|
||||
# take a long time.
|
||||
idle_table_cycle=120
|
||||
populate_threads=5
|
||||
checkpoint_threads=0
|
||||
report_interval=5
|
||||
# 100 million
|
||||
random_range=10000000
|
||||
run_time=300
|
||||
# Setup a workload that dirties a lot of the cache
|
||||
threads=((count=2,reads=1),(count=2,inserts=1),(count=2,updates=1))
|
||||
value_sz=500
|
||||
174
dist/api_data.py
vendored
174
dist/api_data.py
vendored
@@ -420,40 +420,6 @@ connection_runtime_config = [
|
||||
interval in seconds at which to check for files that are
|
||||
inactive and close them''', min=1, max=100000),
|
||||
]),
|
||||
Config('log', '', r'''
|
||||
enable logging. Enabling logging uses three sessions from the
|
||||
configured session_max''',
|
||||
type='category', subconfig=[
|
||||
Config('archive', 'true', r'''
|
||||
automatically archive unneeded log files''',
|
||||
type='boolean'),
|
||||
Config('compressor', 'none', r'''
|
||||
configure a compressor for log records. Permitted values are
|
||||
\c "none" or custom compression engine name created with
|
||||
WT_CONNECTION::add_compressor. If WiredTiger has builtin support
|
||||
for \c "snappy", \c "lz4" or \c "zlib" compression, these names
|
||||
are also available. See @ref compression for more information'''),
|
||||
Config('enabled', 'false', r'''
|
||||
enable logging subsystem''',
|
||||
type='boolean'),
|
||||
Config('file_max', '100MB', r'''
|
||||
the maximum size of log files''',
|
||||
min='100KB', max='2GB'),
|
||||
Config('path', '"."', r'''
|
||||
the path to a directory into which the log files are written.
|
||||
If the value is not an absolute path name, the files are created
|
||||
relative to the database home'''),
|
||||
Config('prealloc', 'true', r'''
|
||||
pre-allocate log files.''',
|
||||
type='boolean'),
|
||||
Config('recover', 'on', r'''
|
||||
run recovery or error if recovery needs to run after an
|
||||
unclean shutdown.''',
|
||||
choices=['error','on']),
|
||||
Config('zero_fill', 'false', r'''
|
||||
manually write zeroes into log files''',
|
||||
type='boolean'),
|
||||
]),
|
||||
Config('lsm_manager', '', r'''
|
||||
configure database wide options for LSM tree management. The LSM
|
||||
manager is started automatically the first time an LSM tree is opened.
|
||||
@@ -525,38 +491,6 @@ connection_runtime_config = [
|
||||
are logged using the \c statistics_log configuration. See
|
||||
@ref statistics for more information''',
|
||||
type='list', choices=['all', 'fast', 'none', 'clear']),
|
||||
Config('statistics_log', '', r'''
|
||||
log any statistics the database is configured to maintain,
|
||||
to a file. See @ref statistics for more information. Enabling
|
||||
the statistics log server uses a session from the configured
|
||||
session_max''',
|
||||
type='category', subconfig=[
|
||||
Config('json', 'false', r'''
|
||||
encode statistics in JSON format''',
|
||||
type='boolean'),
|
||||
Config('on_close', 'false', r'''log statistics on database close''',
|
||||
type='boolean'),
|
||||
Config('path', '"WiredTigerStat.%d.%H"', r'''
|
||||
the pathname to a file into which the log records are written,
|
||||
may contain ISO C standard strftime conversion specifications.
|
||||
If the value is not an absolute path name, the file is created
|
||||
relative to the database home'''),
|
||||
Config('sources', '', r'''
|
||||
if non-empty, include statistics for the list of data source
|
||||
URIs, if they are open at the time of the statistics logging.
|
||||
The list may include URIs matching a single data source
|
||||
("table:mytable"), or a URI matching all data sources of a
|
||||
particular type ("table:")''',
|
||||
type='list'),
|
||||
Config('timestamp', '"%b %d %H:%M:%S"', r'''
|
||||
a timestamp prepended to each log record, may contain strftime
|
||||
conversion specifications, when \c json is configured, defaults
|
||||
to \c "%FT%Y.000Z"'''),
|
||||
Config('wait', '0', r'''
|
||||
seconds to wait between each write of the log records; setting
|
||||
this value above 0 configures statistics logging''',
|
||||
min='0', max='100000'),
|
||||
]),
|
||||
Config('verbose', '', r'''
|
||||
enable messages for various events. Only available if WiredTiger
|
||||
is configured with --enable-verbose. Options are given as a
|
||||
@@ -590,13 +524,113 @@ connection_runtime_config = [
|
||||
'write']),
|
||||
]
|
||||
|
||||
# wiredtiger_open and WT_CONNECTION.reconfigure log configurations.
|
||||
log_configuration_common = [
|
||||
Config('archive', 'true', r'''
|
||||
automatically archive unneeded log files''',
|
||||
type='boolean'),
|
||||
Config('prealloc', 'true', r'''
|
||||
pre-allocate log files.''',
|
||||
type='boolean'),
|
||||
Config('zero_fill', 'false', r'''
|
||||
manually write zeroes into log files''',
|
||||
type='boolean')
|
||||
]
|
||||
connection_reconfigure_log_configuration = [
|
||||
Config('log', '', r'''
|
||||
enable logging. Enabling logging uses three sessions from the
|
||||
configured session_max''',
|
||||
type='category', subconfig=
|
||||
log_configuration_common)
|
||||
]
|
||||
wiredtiger_open_log_configuration = [
|
||||
Config('log', '', r'''
|
||||
enable logging. Enabling logging uses three sessions from the
|
||||
configured session_max''',
|
||||
type='category', subconfig=
|
||||
log_configuration_common + [
|
||||
Config('enabled', 'false', r'''
|
||||
enable logging subsystem''',
|
||||
type='boolean'),
|
||||
Config('compressor', 'none', r'''
|
||||
configure a compressor for log records. Permitted values are
|
||||
\c "none" or custom compression engine name created with
|
||||
WT_CONNECTION::add_compressor. If WiredTiger has builtin support
|
||||
for \c "snappy", \c "lz4" or \c "zlib" compression, these names
|
||||
are also available. See @ref compression for more information'''),
|
||||
Config('file_max', '100MB', r'''
|
||||
the maximum size of log files''',
|
||||
min='100KB', max='2GB'),
|
||||
Config('path', '"."', r'''
|
||||
the name of a directory into which log files are written. The
|
||||
directory must already exist. If the value is not an absolute
|
||||
path, the path is relative to the database home (see @ref
|
||||
absolute_path for more information)'''),
|
||||
Config('recover', 'on', r'''
|
||||
run recovery or error if recovery needs to run after an
|
||||
unclean shutdown''',
|
||||
choices=['error','on'])
|
||||
]),
|
||||
]
|
||||
|
||||
# wiredtiger_open and WT_CONNECTION.reconfigure statistics log configurations.
|
||||
statistics_log_configuration_common = [
|
||||
Config('json', 'false', r'''
|
||||
encode statistics in JSON format''',
|
||||
type='boolean'),
|
||||
Config('on_close', 'false', r'''log statistics on database close''',
|
||||
type='boolean'),
|
||||
Config('sources', '', r'''
|
||||
if non-empty, include statistics for the list of data source
|
||||
URIs, if they are open at the time of the statistics logging.
|
||||
The list may include URIs matching a single data source
|
||||
("table:mytable"), or a URI matching all data sources of a
|
||||
particular type ("table:")''',
|
||||
type='list'),
|
||||
Config('timestamp', '"%b %d %H:%M:%S"', r'''
|
||||
a timestamp prepended to each log record, may contain strftime
|
||||
conversion specifications, when \c json is configured, defaults
|
||||
to \c "%FT%Y.000Z"'''),
|
||||
Config('wait', '0', r'''
|
||||
seconds to wait between each write of the log records; setting
|
||||
this value above 0 configures statistics logging''',
|
||||
min='0', max='100000'),
|
||||
]
|
||||
connection_reconfigure_statistics_log_configuration = [
|
||||
Config('statistics_log', '', r'''
|
||||
log any statistics the database is configured to maintain,
|
||||
to a file. See @ref statistics for more information. Enabling
|
||||
the statistics log server uses a session from the configured
|
||||
session_max''',
|
||||
type='category', subconfig=
|
||||
statistics_log_configuration_common)
|
||||
]
|
||||
wiredtiger_open_statistics_log_configuration = [
|
||||
Config('statistics_log', '', r'''
|
||||
log any statistics the database is configured to maintain,
|
||||
to a file. See @ref statistics for more information. Enabling
|
||||
the statistics log server uses a session from the configured
|
||||
session_max''',
|
||||
type='category', subconfig=
|
||||
statistics_log_configuration_common + [
|
||||
Config('path', '"."', r'''
|
||||
the name of a directory into which statistics files are written.
|
||||
The directory must already exist. If the value is not an absolute
|
||||
path, the path is relative to the database home (see @ref
|
||||
absolute_path for more information)''')
|
||||
])
|
||||
]
|
||||
|
||||
session_config = [
|
||||
Config('isolation', 'read-committed', r'''
|
||||
the default isolation level for operations in this session''',
|
||||
choices=['read-uncommitted', 'read-committed', 'snapshot']),
|
||||
]
|
||||
|
||||
wiredtiger_open_common = connection_runtime_config + [
|
||||
wiredtiger_open_common =\
|
||||
connection_runtime_config +\
|
||||
wiredtiger_open_log_configuration +\
|
||||
wiredtiger_open_statistics_log_configuration + [
|
||||
Config('buffer_alignment', '-1', r'''
|
||||
in-memory alignment (in bytes) for buffers used for I/O. The
|
||||
default value of -1 indicates a platform-specific alignment value
|
||||
@@ -1084,7 +1118,11 @@ methods = {
|
||||
don't free memory during close''',
|
||||
type='boolean'),
|
||||
]),
|
||||
'WT_CONNECTION.reconfigure' : Method(connection_runtime_config),
|
||||
'WT_CONNECTION.reconfigure' : Method(
|
||||
connection_reconfigure_log_configuration +\
|
||||
connection_reconfigure_statistics_log_configuration +\
|
||||
connection_runtime_config
|
||||
),
|
||||
'WT_CONNECTION.set_file_system' : Method([]),
|
||||
|
||||
'WT_CONNECTION.load_extension' : Method([
|
||||
|
||||
7
dist/s_string.ok
vendored
7
dist/s_string.ok
vendored
@@ -86,6 +86,7 @@ DbEnv
|
||||
Decrement
|
||||
Decrypt
|
||||
DeleteFileA
|
||||
EACCES
|
||||
EAGAIN
|
||||
EB
|
||||
EBUSY
|
||||
@@ -117,6 +118,7 @@ FLv
|
||||
FNV
|
||||
FORALL
|
||||
FOREACH
|
||||
FS
|
||||
FULLFSYNC
|
||||
FindClose
|
||||
FindFirstFile
|
||||
@@ -326,6 +328,7 @@ UID
|
||||
UIDs
|
||||
UINT
|
||||
ULINE
|
||||
UNC
|
||||
URI
|
||||
URIs
|
||||
UTF
|
||||
@@ -528,6 +531,7 @@ cust
|
||||
customp
|
||||
cv
|
||||
cxa
|
||||
dT
|
||||
data's
|
||||
database's
|
||||
datalen
|
||||
@@ -557,6 +561,7 @@ dequeued
|
||||
der
|
||||
dereference
|
||||
desc
|
||||
designator
|
||||
dest
|
||||
destSize
|
||||
dev
|
||||
@@ -1065,6 +1070,7 @@ tV
|
||||
tablename
|
||||
tcbench
|
||||
td
|
||||
tempdir
|
||||
testutil
|
||||
th
|
||||
tid
|
||||
@@ -1091,6 +1097,7 @@ txn
|
||||
txnc
|
||||
txnid
|
||||
txnmin
|
||||
txt
|
||||
typedef
|
||||
uB
|
||||
uS
|
||||
|
||||
@@ -1160,34 +1160,27 @@ main(void)
|
||||
if (ret == 0)
|
||||
(void)conn->close(conn, NULL);
|
||||
|
||||
#ifdef MIGHT_NOT_RUN
|
||||
/*
|
||||
* Don't run this code, statistics logging doesn't yet support tables.
|
||||
*/
|
||||
/*! [Statistics logging with a table] */
|
||||
ret = wiredtiger_open(home, NULL,
|
||||
"create, statistics_log=("
|
||||
"sources=(\"lsm:table1\",\"lsm:table2\"), wait=5)",
|
||||
"sources=(\"table:table1\",\"table:table2\"), wait=5)",
|
||||
&conn);
|
||||
/*! [Statistics logging with a table] */
|
||||
if (ret == 0)
|
||||
(void)conn->close(conn, NULL);
|
||||
|
||||
/*! [Statistics logging with all tables] */
|
||||
ret = wiredtiger_open(home, NULL,
|
||||
"create, statistics_log=(sources=(\"lsm:\"), wait=5)",
|
||||
&conn);
|
||||
/*! [Statistics logging with all tables] */
|
||||
if (ret == 0)
|
||||
(void)conn->close(conn, NULL);
|
||||
|
||||
#ifdef MIGHT_NOT_RUN
|
||||
/*
|
||||
* This example code gets run, and a non-existent log file path might
|
||||
* cause the open to fail. The documentation requires code snippets,
|
||||
* use #ifdef's to avoid running it.
|
||||
* Don't run this code, statistics logging doesn't yet support indexes.
|
||||
*/
|
||||
/*! [Statistics logging with path] */
|
||||
/*! [Statistics logging with a source type] */
|
||||
ret = wiredtiger_open(home, NULL,
|
||||
"create,"
|
||||
"statistics_log=(wait=120,path=/log/log.%m.%d.%y)", &conn);
|
||||
/*! [Statistics logging with path] */
|
||||
"create, statistics_log=(sources=(\"index:\"), wait=5)",
|
||||
&conn);
|
||||
/*! [Statistics logging with a source type] */
|
||||
if (ret == 0)
|
||||
(void)conn->close(conn, NULL);
|
||||
|
||||
|
||||
@@ -118,18 +118,17 @@ int demo_file_system_create(WT_CONNECTION *, WT_CONFIG_ARG *);
|
||||
/*
|
||||
* Forward function declarations for file system API implementation
|
||||
*/
|
||||
static int demo_fs_open(WT_FILE_SYSTEM *,
|
||||
WT_SESSION *, const char *, WT_OPEN_FILE_TYPE, uint32_t, WT_FILE_HANDLE **);
|
||||
static int demo_fs_open(WT_FILE_SYSTEM *, WT_SESSION *,
|
||||
const char *, WT_FS_OPEN_FILE_TYPE, uint32_t, WT_FILE_HANDLE **);
|
||||
static int demo_fs_directory_list(WT_FILE_SYSTEM *, WT_SESSION *,
|
||||
const char *, const char *, char ***, uint32_t *);
|
||||
static int demo_fs_directory_list_free(
|
||||
WT_FILE_SYSTEM *, WT_SESSION *, char **, uint32_t);
|
||||
static int demo_fs_directory_sync(WT_FILE_SYSTEM *file_system,
|
||||
WT_SESSION *session, const char *directory);
|
||||
static int demo_fs_exist(WT_FILE_SYSTEM *, WT_SESSION *, const char *, bool *);
|
||||
static int demo_fs_remove(WT_FILE_SYSTEM *, WT_SESSION *, const char *);
|
||||
static int demo_fs_remove(
|
||||
WT_FILE_SYSTEM *, WT_SESSION *, const char *, uint32_t);
|
||||
static int demo_fs_rename(
|
||||
WT_FILE_SYSTEM *, WT_SESSION *, const char *, const char *);
|
||||
WT_FILE_SYSTEM *, WT_SESSION *, const char *, const char *, uint32_t);
|
||||
static int demo_fs_size(
|
||||
WT_FILE_SYSTEM *, WT_SESSION *, const char *, wt_off_t *);
|
||||
static int demo_fs_terminate(WT_FILE_SYSTEM *, WT_SESSION *);
|
||||
@@ -255,7 +254,6 @@ demo_file_system_create(WT_CONNECTION *conn, WT_CONFIG_ARG *config)
|
||||
/* Initialize the in-memory jump table. */
|
||||
file_system->fs_directory_list = demo_fs_directory_list;
|
||||
file_system->fs_directory_list_free = demo_fs_directory_list_free;
|
||||
file_system->fs_directory_sync = demo_fs_directory_sync;
|
||||
file_system->fs_exist = demo_fs_exist;
|
||||
file_system->fs_open_file = demo_fs_open;
|
||||
file_system->fs_remove = demo_fs_remove;
|
||||
@@ -282,7 +280,7 @@ err: free(demo_fs);
|
||||
*/
|
||||
static int
|
||||
demo_fs_open(WT_FILE_SYSTEM *file_system, WT_SESSION *session,
|
||||
const char *name, WT_OPEN_FILE_TYPE file_type, uint32_t flags,
|
||||
const char *name, WT_FS_OPEN_FILE_TYPE file_type, uint32_t flags,
|
||||
WT_FILE_HANDLE **file_handlep)
|
||||
{
|
||||
DEMO_FILE_HANDLE *demo_fh;
|
||||
@@ -468,21 +466,6 @@ demo_fs_directory_list_free(WT_FILE_SYSTEM *file_system,
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* demo_fs_directory_sync --
|
||||
* Directory sync for our demo file system, which is a no-op.
|
||||
*/
|
||||
static int
|
||||
demo_fs_directory_sync(WT_FILE_SYSTEM *file_system,
|
||||
WT_SESSION *session, const char *directory)
|
||||
{
|
||||
(void)file_system; /* Unused */
|
||||
(void)session; /* Unused */
|
||||
(void)directory; /* Unused */
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* demo_fs_exist --
|
||||
* Return if the file exists.
|
||||
@@ -507,13 +490,15 @@ demo_fs_exist(WT_FILE_SYSTEM *file_system,
|
||||
* POSIX remove.
|
||||
*/
|
||||
static int
|
||||
demo_fs_remove(
|
||||
WT_FILE_SYSTEM *file_system, WT_SESSION *session, const char *name)
|
||||
demo_fs_remove(WT_FILE_SYSTEM *file_system,
|
||||
WT_SESSION *session, const char *name, uint32_t flags)
|
||||
{
|
||||
DEMO_FILE_SYSTEM *demo_fs;
|
||||
DEMO_FILE_HANDLE *demo_fh;
|
||||
int ret = 0;
|
||||
|
||||
(void)flags; /* Unused */
|
||||
|
||||
demo_fs = (DEMO_FILE_SYSTEM *)file_system;
|
||||
|
||||
ret = ENOENT;
|
||||
@@ -531,13 +516,15 @@ demo_fs_remove(
|
||||
*/
|
||||
static int
|
||||
demo_fs_rename(WT_FILE_SYSTEM *file_system,
|
||||
WT_SESSION *session, const char *from, const char *to)
|
||||
WT_SESSION *session, const char *from, const char *to, uint32_t flags)
|
||||
{
|
||||
DEMO_FILE_HANDLE *demo_fh;
|
||||
DEMO_FILE_SYSTEM *demo_fs;
|
||||
char *copy;
|
||||
int ret = 0;
|
||||
|
||||
(void)flags; /* Unused */
|
||||
|
||||
demo_fs = (DEMO_FILE_SYSTEM *)file_system;
|
||||
|
||||
LOCK_FILE_SYSTEM(session, demo_fs);
|
||||
|
||||
@@ -988,6 +988,10 @@ allExample()
|
||||
/*! [Statistics logging] */
|
||||
conn.close(null);
|
||||
|
||||
if (false) { // MIGHT_NOT_RUN
|
||||
/*
|
||||
* Don't run this code, statistics logging doesn't yet support tables.
|
||||
*/
|
||||
/*! [Statistics logging with a table] */
|
||||
conn = wiredtiger.open(home,
|
||||
"create," +
|
||||
@@ -995,23 +999,13 @@ allExample()
|
||||
/*! [Statistics logging with a table] */
|
||||
conn.close(null);
|
||||
|
||||
/*! [Statistics logging with all tables] */
|
||||
conn = wiredtiger.open(home,
|
||||
"create,statistics_log=(sources=(\"table:\"))");
|
||||
/*! [Statistics logging with all tables] */
|
||||
conn.close(null);
|
||||
|
||||
if (false) { // MIGHT_NOT_RUN
|
||||
/*
|
||||
* This example code gets run, and a non-existent log file path might
|
||||
* cause the open to fail. The documentation requires code snippets,
|
||||
* use if (false) to avoid running it.
|
||||
* Don't run this code, statistics logging doesn't yet support indexes.
|
||||
*/
|
||||
/*! [Statistics logging with path] */
|
||||
/*! [Statistics logging with a source type] */
|
||||
conn = wiredtiger.open(home,
|
||||
"create," +
|
||||
"statistics_log=(wait=120,path=/log/log.%m.%d.%y)");
|
||||
/*! [Statistics logging with path] */
|
||||
"create,statistics_log=(sources=(\"index:\"))");
|
||||
/*! [Statistics logging with a source type] */
|
||||
conn.close(null);
|
||||
|
||||
/*
|
||||
|
||||
@@ -15,9 +15,10 @@ static int __desc_read(WT_SESSION_IMPL *, WT_BLOCK *);
|
||||
* Drop a file.
|
||||
*/
|
||||
int
|
||||
__wt_block_manager_drop(WT_SESSION_IMPL *session, const char *filename)
|
||||
__wt_block_manager_drop(
|
||||
WT_SESSION_IMPL *session, const char *filename, bool durable)
|
||||
{
|
||||
return (__wt_remove_if_exists(session, filename));
|
||||
return (__wt_remove_if_exists(session, filename, durable));
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -43,8 +44,9 @@ __wt_block_manager_create(
|
||||
* in our space. Move any existing files out of the way and complain.
|
||||
*/
|
||||
for (;;) {
|
||||
if ((ret = __wt_open(session, filename, WT_OPEN_FILE_TYPE_DATA,
|
||||
WT_OPEN_CREATE | WT_OPEN_EXCLUSIVE, &fh)) == 0)
|
||||
if ((ret = __wt_open(session, filename,
|
||||
WT_FS_OPEN_FILE_TYPE_DATA, WT_FS_OPEN_CREATE |
|
||||
WT_FS_OPEN_DURABLE | WT_FS_OPEN_EXCLUSIVE, &fh)) == 0)
|
||||
break;
|
||||
WT_ERR_TEST(ret != EEXIST, ret);
|
||||
|
||||
@@ -56,7 +58,7 @@ __wt_block_manager_create(
|
||||
WT_ERR(__wt_fs_exist(session, tmp->data, &exists));
|
||||
if (!exists) {
|
||||
WT_ERR(__wt_fs_rename(
|
||||
session, filename, tmp->data));
|
||||
session, filename, tmp->data, false));
|
||||
WT_ERR(__wt_msg(session,
|
||||
"unexpected file %s found, renamed to %s",
|
||||
filename, (const char *)tmp->data));
|
||||
@@ -77,16 +79,9 @@ __wt_block_manager_create(
|
||||
/* Close the file handle. */
|
||||
WT_TRET(__wt_close(session, &fh));
|
||||
|
||||
/*
|
||||
* Some filesystems require that we sync the directory to be confident
|
||||
* that the file will appear.
|
||||
*/
|
||||
if (ret == 0)
|
||||
WT_TRET(__wt_fs_directory_sync(session, filename));
|
||||
|
||||
/* Undo any create on error. */
|
||||
if (ret != 0)
|
||||
WT_TRET(__wt_fs_remove(session, filename));
|
||||
WT_TRET(__wt_fs_remove(session, filename, false));
|
||||
|
||||
err: __wt_scr_free(session, &tmp);
|
||||
|
||||
@@ -207,11 +202,11 @@ __wt_block_open(WT_SESSION_IMPL *session,
|
||||
*/
|
||||
flags = 0;
|
||||
if (readonly && FLD_ISSET(conn->direct_io, WT_DIRECT_IO_CHECKPOINT))
|
||||
LF_SET(WT_OPEN_DIRECTIO);
|
||||
LF_SET(WT_FS_OPEN_DIRECTIO);
|
||||
if (!readonly && FLD_ISSET(conn->direct_io, WT_DIRECT_IO_DATA))
|
||||
LF_SET(WT_OPEN_DIRECTIO);
|
||||
LF_SET(WT_FS_OPEN_DIRECTIO);
|
||||
WT_ERR(__wt_open(
|
||||
session, filename, WT_OPEN_FILE_TYPE_DATA, flags, &block->fh));
|
||||
session, filename, WT_FS_OPEN_FILE_TYPE_DATA, flags, &block->fh));
|
||||
|
||||
/* Set the file's size. */
|
||||
WT_ERR(__wt_filesize(session, block->fh, &block->size));
|
||||
|
||||
@@ -183,6 +183,7 @@ __cursor_var_next(WT_CURSOR_BTREE *cbt, bool newpage)
|
||||
if (cbt->last_standard_recno == 0)
|
||||
return (WT_NOTFOUND);
|
||||
__cursor_set_recno(cbt, cbt->ref->ref_recno);
|
||||
cbt->cip_saved = NULL;
|
||||
goto new_page;
|
||||
}
|
||||
|
||||
@@ -301,12 +302,13 @@ __cursor_row_next(WT_CURSOR_BTREE *cbt, bool newpage)
|
||||
* WT_INSERT_HEAD[0], and so on. This means WT_INSERT lists are
|
||||
* odd-numbered slots, and WT_ROW array slots are even-numbered slots.
|
||||
*
|
||||
* New page configuration.
|
||||
* Initialize for each new page.
|
||||
*/
|
||||
if (newpage) {
|
||||
cbt->ins_head = WT_ROW_INSERT_SMALLEST(page);
|
||||
cbt->ins = WT_SKIP_FIRST(cbt->ins_head);
|
||||
cbt->row_iteration_slot = 1;
|
||||
cbt->rip_saved = NULL;
|
||||
goto new_insert;
|
||||
}
|
||||
|
||||
@@ -517,11 +519,13 @@ __wt_btcur_iterate_setup(WT_CURSOR_BTREE *cbt)
|
||||
*/
|
||||
F_SET(cbt, WT_CBT_ITERATE_NEXT | WT_CBT_ITERATE_PREV);
|
||||
|
||||
/*
|
||||
* Clear the count of deleted items on the page.
|
||||
*/
|
||||
/* Clear the count of deleted items on the page. */
|
||||
cbt->page_deleted_count = 0;
|
||||
|
||||
/* Clear saved iteration cursor position information. */
|
||||
cbt->cip_saved = NULL;
|
||||
cbt->rip_saved = NULL;
|
||||
|
||||
/*
|
||||
* If we don't have a search page, then we're done, we're starting at
|
||||
* the beginning or end of the tree, not as a result of a search.
|
||||
|
||||
@@ -329,6 +329,7 @@ __cursor_var_prev(WT_CURSOR_BTREE *cbt, bool newpage)
|
||||
if (cbt->last_standard_recno == 0)
|
||||
return (WT_NOTFOUND);
|
||||
__cursor_set_recno(cbt, cbt->last_standard_recno);
|
||||
cbt->cip_saved = NULL;
|
||||
goto new_page;
|
||||
}
|
||||
|
||||
@@ -447,7 +448,7 @@ __cursor_row_prev(WT_CURSOR_BTREE *cbt, bool newpage)
|
||||
* WT_INSERT_HEAD[0], and so on. This means WT_INSERT lists are
|
||||
* odd-numbered slots, and WT_ROW array slots are even-numbered slots.
|
||||
*
|
||||
* New page configuration.
|
||||
* Initialize for each new page.
|
||||
*/
|
||||
if (newpage) {
|
||||
/*
|
||||
@@ -464,6 +465,7 @@ __cursor_row_prev(WT_CURSOR_BTREE *cbt, bool newpage)
|
||||
WT_ROW_INSERT_SLOT(page, page->pg_row_entries - 1);
|
||||
cbt->ins = WT_SKIP_LAST(cbt->ins_head);
|
||||
cbt->row_iteration_slot = page->pg_row_entries * 2 + 1;
|
||||
cbt->rip_saved = NULL;
|
||||
goto new_insert;
|
||||
}
|
||||
|
||||
|
||||
@@ -157,7 +157,8 @@ __huffman_confchk_file(WT_SESSION_IMPL *session,
|
||||
|
||||
/* Check the file exists. */
|
||||
WT_RET(__wt_strndup(session, v->str + len, v->len - len, &fname));
|
||||
WT_ERR(__wt_fopen(session, fname, WT_OPEN_FIXED, WT_STREAM_READ, &fs));
|
||||
WT_ERR(__wt_fopen(
|
||||
session, fname, WT_FS_OPEN_FIXED, WT_STREAM_READ, &fs));
|
||||
|
||||
/* Optionally return the file handle. */
|
||||
if (fsp == NULL)
|
||||
|
||||
@@ -67,16 +67,9 @@ static const WT_CONFIG_CHECK
|
||||
};
|
||||
|
||||
static const WT_CONFIG_CHECK
|
||||
confchk_wiredtiger_open_log_subconfigs[] = {
|
||||
confchk_WT_CONNECTION_reconfigure_log_subconfigs[] = {
|
||||
{ "archive", "boolean", NULL, NULL, NULL, 0 },
|
||||
{ "compressor", "string", NULL, NULL, NULL, 0 },
|
||||
{ "enabled", "boolean", NULL, NULL, NULL, 0 },
|
||||
{ "file_max", "int", NULL, "min=100KB,max=2GB", NULL, 0 },
|
||||
{ "path", "string", NULL, NULL, NULL, 0 },
|
||||
{ "prealloc", "boolean", NULL, NULL, NULL, 0 },
|
||||
{ "recover", "string",
|
||||
NULL, "choices=[\"error\",\"on\"]",
|
||||
NULL, 0 },
|
||||
{ "zero_fill", "boolean", NULL, NULL, NULL, 0 },
|
||||
{ NULL, NULL, NULL, NULL, NULL, 0 }
|
||||
};
|
||||
@@ -99,10 +92,9 @@ static const WT_CONFIG_CHECK
|
||||
};
|
||||
|
||||
static const WT_CONFIG_CHECK
|
||||
confchk_wiredtiger_open_statistics_log_subconfigs[] = {
|
||||
confchk_WT_CONNECTION_reconfigure_statistics_log_subconfigs[] = {
|
||||
{ "json", "boolean", NULL, NULL, NULL, 0 },
|
||||
{ "on_close", "boolean", NULL, NULL, NULL, 0 },
|
||||
{ "path", "string", NULL, NULL, NULL, 0 },
|
||||
{ "sources", "list", NULL, NULL, NULL, 0 },
|
||||
{ "timestamp", "string", NULL, NULL, NULL, 0 },
|
||||
{ "wait", "int", NULL, "min=0,max=100000", NULL, 0 },
|
||||
@@ -135,7 +127,7 @@ static const WT_CONFIG_CHECK confchk_WT_CONNECTION_reconfigure[] = {
|
||||
confchk_wiredtiger_open_file_manager_subconfigs, 3 },
|
||||
{ "log", "category",
|
||||
NULL, NULL,
|
||||
confchk_wiredtiger_open_log_subconfigs, 8 },
|
||||
confchk_WT_CONNECTION_reconfigure_log_subconfigs, 3 },
|
||||
{ "lsm_manager", "category",
|
||||
NULL, NULL,
|
||||
confchk_wiredtiger_open_lsm_manager_subconfigs, 2 },
|
||||
@@ -148,7 +140,7 @@ static const WT_CONFIG_CHECK confchk_WT_CONNECTION_reconfigure[] = {
|
||||
NULL, 0 },
|
||||
{ "statistics_log", "category",
|
||||
NULL, NULL,
|
||||
confchk_wiredtiger_open_statistics_log_subconfigs, 6 },
|
||||
confchk_WT_CONNECTION_reconfigure_statistics_log_subconfigs, 5 },
|
||||
{ "verbose", "list",
|
||||
NULL, "choices=[\"api\",\"block\",\"checkpoint\",\"compact\","
|
||||
"\"evict\",\"evictserver\",\"fileops\",\"handleops\",\"log\","
|
||||
@@ -607,6 +599,32 @@ static const WT_CONFIG_CHECK
|
||||
{ NULL, NULL, NULL, NULL, NULL, 0 }
|
||||
};
|
||||
|
||||
static const WT_CONFIG_CHECK
|
||||
confchk_wiredtiger_open_log_subconfigs[] = {
|
||||
{ "archive", "boolean", NULL, NULL, NULL, 0 },
|
||||
{ "compressor", "string", NULL, NULL, NULL, 0 },
|
||||
{ "enabled", "boolean", NULL, NULL, NULL, 0 },
|
||||
{ "file_max", "int", NULL, "min=100KB,max=2GB", NULL, 0 },
|
||||
{ "path", "string", NULL, NULL, NULL, 0 },
|
||||
{ "prealloc", "boolean", NULL, NULL, NULL, 0 },
|
||||
{ "recover", "string",
|
||||
NULL, "choices=[\"error\",\"on\"]",
|
||||
NULL, 0 },
|
||||
{ "zero_fill", "boolean", NULL, NULL, NULL, 0 },
|
||||
{ NULL, NULL, NULL, NULL, NULL, 0 }
|
||||
};
|
||||
|
||||
static const WT_CONFIG_CHECK
|
||||
confchk_wiredtiger_open_statistics_log_subconfigs[] = {
|
||||
{ "json", "boolean", NULL, NULL, NULL, 0 },
|
||||
{ "on_close", "boolean", NULL, NULL, NULL, 0 },
|
||||
{ "path", "string", NULL, NULL, NULL, 0 },
|
||||
{ "sources", "list", NULL, NULL, NULL, 0 },
|
||||
{ "timestamp", "string", NULL, NULL, NULL, 0 },
|
||||
{ "wait", "int", NULL, "min=0,max=100000", NULL, 0 },
|
||||
{ NULL, NULL, NULL, NULL, NULL, 0 }
|
||||
};
|
||||
|
||||
static const WT_CONFIG_CHECK
|
||||
confchk_wiredtiger_open_transaction_sync_subconfigs[] = {
|
||||
{ "enabled", "boolean", NULL, NULL, NULL, 0 },
|
||||
@@ -975,12 +993,10 @@ static const WT_CONFIG_ENTRY config_entries[] = {
|
||||
"eviction=(threads_max=1,threads_min=1),eviction_dirty_target=80,"
|
||||
"eviction_dirty_trigger=95,eviction_target=80,eviction_trigger=95"
|
||||
",file_manager=(close_handle_minimum=250,close_idle_time=30,"
|
||||
"close_scan_interval=10),log=(archive=,compressor=,enabled=0,"
|
||||
"file_max=100MB,path=\".\",prealloc=,recover=on,zero_fill=0),"
|
||||
"close_scan_interval=10),log=(archive=,prealloc=,zero_fill=0),"
|
||||
"lsm_manager=(merge=,worker_thread_max=4),lsm_merge=,"
|
||||
"shared_cache=(chunk=10MB,name=,quota=0,reserve=0,size=500MB),"
|
||||
"statistics=none,statistics_log=(json=0,on_close=0,"
|
||||
"path=\"WiredTigerStat.%d.%H\",sources=,"
|
||||
"statistics=none,statistics_log=(json=0,on_close=0,sources=,"
|
||||
"timestamp=\"%b %d %H:%M:%S\",wait=0),verbose=",
|
||||
confchk_WT_CONNECTION_reconfigure, 18
|
||||
},
|
||||
@@ -1181,11 +1197,10 @@ static const WT_CONFIG_ENTRY config_entries[] = {
|
||||
",worker_thread_max=4),lsm_merge=,mmap=,multiprocess=0,readonly=0"
|
||||
",session_max=100,session_scratch_max=2MB,"
|
||||
"shared_cache=(chunk=10MB,name=,quota=0,reserve=0,size=500MB),"
|
||||
"statistics=none,statistics_log=(json=0,on_close=0,"
|
||||
"path=\"WiredTigerStat.%d.%H\",sources=,"
|
||||
"timestamp=\"%b %d %H:%M:%S\",wait=0),transaction_sync=(enabled=0"
|
||||
",method=fsync),use_environment=,use_environment_priv=0,verbose=,"
|
||||
"write_through=",
|
||||
"statistics=none,statistics_log=(json=0,on_close=0,path=\".\","
|
||||
"sources=,timestamp=\"%b %d %H:%M:%S\",wait=0),"
|
||||
"transaction_sync=(enabled=0,method=fsync),use_environment=,"
|
||||
"use_environment_priv=0,verbose=,write_through=",
|
||||
confchk_wiredtiger_open, 38
|
||||
},
|
||||
{ "wiredtiger_open_all",
|
||||
@@ -1203,11 +1218,11 @@ static const WT_CONFIG_ENTRY config_entries[] = {
|
||||
",worker_thread_max=4),lsm_merge=,mmap=,multiprocess=0,readonly=0"
|
||||
",session_max=100,session_scratch_max=2MB,"
|
||||
"shared_cache=(chunk=10MB,name=,quota=0,reserve=0,size=500MB),"
|
||||
"statistics=none,statistics_log=(json=0,on_close=0,"
|
||||
"path=\"WiredTigerStat.%d.%H\",sources=,"
|
||||
"timestamp=\"%b %d %H:%M:%S\",wait=0),transaction_sync=(enabled=0"
|
||||
",method=fsync),use_environment=,use_environment_priv=0,verbose=,"
|
||||
"version=(major=0,minor=0),write_through=",
|
||||
"statistics=none,statistics_log=(json=0,on_close=0,path=\".\","
|
||||
"sources=,timestamp=\"%b %d %H:%M:%S\",wait=0),"
|
||||
"transaction_sync=(enabled=0,method=fsync),use_environment=,"
|
||||
"use_environment_priv=0,verbose=,version=(major=0,minor=0),"
|
||||
"write_through=",
|
||||
confchk_wiredtiger_open_all, 39
|
||||
},
|
||||
{ "wiredtiger_open_basecfg",
|
||||
@@ -1224,10 +1239,9 @@ static const WT_CONFIG_ENTRY config_entries[] = {
|
||||
"worker_thread_max=4),lsm_merge=,mmap=,multiprocess=0,readonly=0,"
|
||||
"session_max=100,session_scratch_max=2MB,shared_cache=(chunk=10MB"
|
||||
",name=,quota=0,reserve=0,size=500MB),statistics=none,"
|
||||
"statistics_log=(json=0,on_close=0,path=\"WiredTigerStat.%d.%H\","
|
||||
"sources=,timestamp=\"%b %d %H:%M:%S\",wait=0),"
|
||||
"transaction_sync=(enabled=0,method=fsync),verbose=,"
|
||||
"version=(major=0,minor=0),write_through=",
|
||||
"statistics_log=(json=0,on_close=0,path=\".\",sources=,"
|
||||
"timestamp=\"%b %d %H:%M:%S\",wait=0),transaction_sync=(enabled=0"
|
||||
",method=fsync),verbose=,version=(major=0,minor=0),write_through=",
|
||||
confchk_wiredtiger_open_basecfg, 33
|
||||
},
|
||||
{ "wiredtiger_open_usercfg",
|
||||
@@ -1244,10 +1258,9 @@ static const WT_CONFIG_ENTRY config_entries[] = {
|
||||
"worker_thread_max=4),lsm_merge=,mmap=,multiprocess=0,readonly=0,"
|
||||
"session_max=100,session_scratch_max=2MB,shared_cache=(chunk=10MB"
|
||||
",name=,quota=0,reserve=0,size=500MB),statistics=none,"
|
||||
"statistics_log=(json=0,on_close=0,path=\"WiredTigerStat.%d.%H\","
|
||||
"sources=,timestamp=\"%b %d %H:%M:%S\",wait=0),"
|
||||
"transaction_sync=(enabled=0,method=fsync),verbose=,"
|
||||
"write_through=",
|
||||
"statistics_log=(json=0,on_close=0,path=\".\",sources=,"
|
||||
"timestamp=\"%b %d %H:%M:%S\",wait=0),transaction_sync=(enabled=0"
|
||||
",method=fsync),verbose=,write_through=",
|
||||
confchk_wiredtiger_open_usercfg, 32
|
||||
},
|
||||
{ NULL, NULL, NULL, 0 }
|
||||
|
||||
@@ -1217,7 +1217,8 @@ __conn_config_file(WT_SESSION_IMPL *session,
|
||||
return (0);
|
||||
|
||||
/* Open the configuration file. */
|
||||
WT_RET(__wt_open(session, filename, WT_OPEN_FILE_TYPE_REGULAR, 0, &fh));
|
||||
WT_RET(__wt_open(
|
||||
session, filename, WT_FS_OPEN_FILE_TYPE_REGULAR, 0, &fh));
|
||||
WT_ERR(__wt_filesize(session, fh, &size));
|
||||
if (size == 0)
|
||||
goto err;
|
||||
@@ -1510,8 +1511,8 @@ __conn_single(WT_SESSION_IMPL *session, const char *cfg[])
|
||||
exist = false;
|
||||
if (!is_create)
|
||||
WT_ERR(__wt_fs_exist(session, WT_WIREDTIGER, &exist));
|
||||
ret = __wt_open(session, WT_SINGLETHREAD, WT_OPEN_FILE_TYPE_REGULAR,
|
||||
is_create || exist ? WT_OPEN_CREATE : 0, &conn->lock_fh);
|
||||
ret = __wt_open(session, WT_SINGLETHREAD, WT_FS_OPEN_FILE_TYPE_REGULAR,
|
||||
is_create || exist ? WT_FS_OPEN_CREATE : 0, &conn->lock_fh);
|
||||
|
||||
/*
|
||||
* If this is a read-only connection and we cannot grab the lock
|
||||
@@ -1563,7 +1564,8 @@ __conn_single(WT_SESSION_IMPL *session, const char *cfg[])
|
||||
|
||||
/* We own the lock file, optionally create the WiredTiger file. */
|
||||
ret = __wt_open(session, WT_WIREDTIGER,
|
||||
WT_OPEN_FILE_TYPE_REGULAR, is_create ? WT_OPEN_CREATE : 0, &fh);
|
||||
WT_FS_OPEN_FILE_TYPE_REGULAR, is_create ? WT_FS_OPEN_CREATE : 0,
|
||||
&fh);
|
||||
|
||||
/*
|
||||
* If we're read-only, check for handled errors. Even if able to open
|
||||
@@ -1784,7 +1786,7 @@ __conn_write_base_config(WT_SESSION_IMPL *session, const char *cfg[])
|
||||
* runs. This doesn't matter for correctness, it's just cleaning up
|
||||
* random files.
|
||||
*/
|
||||
WT_RET(__wt_remove_if_exists(session, WT_BASECONFIG_SET));
|
||||
WT_RET(__wt_remove_if_exists(session, WT_BASECONFIG_SET, false));
|
||||
|
||||
/*
|
||||
* The base configuration file is only written if creating the database,
|
||||
@@ -1809,7 +1811,7 @@ __conn_write_base_config(WT_SESSION_IMPL *session, const char *cfg[])
|
||||
return (0);
|
||||
|
||||
WT_RET(__wt_fopen(session, WT_BASECONFIG_SET,
|
||||
WT_OPEN_CREATE | WT_OPEN_EXCLUSIVE, WT_STREAM_WRITE, &fs));
|
||||
WT_FS_OPEN_CREATE | WT_FS_OPEN_EXCLUSIVE, WT_STREAM_WRITE, &fs));
|
||||
|
||||
WT_ERR(__wt_fprintf(session, fs, "%s\n\n",
|
||||
"# Do not modify this file.\n"
|
||||
@@ -1870,7 +1872,8 @@ __conn_write_base_config(WT_SESSION_IMPL *session, const char *cfg[])
|
||||
if (0) {
|
||||
/* Close open file handle, remove any temporary file. */
|
||||
err: WT_TRET(__wt_fclose(session, &fs));
|
||||
WT_TRET(__wt_remove_if_exists(session, WT_BASECONFIG_SET));
|
||||
WT_TRET(
|
||||
__wt_remove_if_exists(session, WT_BASECONFIG_SET, false));
|
||||
}
|
||||
|
||||
__wt_free(session, base_config);
|
||||
|
||||
@@ -23,37 +23,16 @@ __ckpt_server_config(WT_SESSION_IMPL *session, const char **cfg, bool *startp)
|
||||
WT_DECL_RET;
|
||||
char *p;
|
||||
|
||||
*startp = false;
|
||||
|
||||
conn = S2C(session);
|
||||
|
||||
/*
|
||||
* The checkpoint configuration requires a wait time and/or a log
|
||||
* size -- if one is not set, we're not running at all.
|
||||
* Checkpoints based on log size also require logging be enabled.
|
||||
*/
|
||||
WT_RET(__wt_config_gets(session, cfg, "checkpoint.wait", &cval));
|
||||
conn->ckpt_usecs = (uint64_t)cval.val * WT_MILLION;
|
||||
|
||||
WT_RET(__wt_config_gets(session, cfg, "checkpoint.log_size", &cval));
|
||||
conn->ckpt_logsize = (wt_off_t)cval.val;
|
||||
|
||||
/* Checkpoints are incompatible with in-memory configuration */
|
||||
if (conn->ckpt_usecs != 0 || conn->ckpt_logsize != 0) {
|
||||
WT_RET(__wt_config_gets(session, cfg, "in_memory", &cval));
|
||||
if (cval.val != 0)
|
||||
WT_RET_MSG(session, EINVAL,
|
||||
"In memory configuration incompatible with "
|
||||
"checkpoints");
|
||||
}
|
||||
|
||||
__wt_log_written_reset(session);
|
||||
if ((conn->ckpt_usecs == 0 && conn->ckpt_logsize == 0) ||
|
||||
(conn->ckpt_logsize && conn->ckpt_usecs == 0 &&
|
||||
!FLD_ISSET(conn->log_flags, WT_CONN_LOG_ENABLED))) {
|
||||
*startp = false;
|
||||
return (0);
|
||||
}
|
||||
*startp = true;
|
||||
|
||||
/*
|
||||
* The application can specify a checkpoint name, which we ignore if
|
||||
* it's our default.
|
||||
@@ -72,6 +51,26 @@ __ckpt_server_config(WT_SESSION_IMPL *session, const char **cfg, bool *startp)
|
||||
conn->ckpt_config = p;
|
||||
}
|
||||
|
||||
/*
|
||||
* The checkpoint configuration requires a wait time and/or a log size,
|
||||
* if neither is set, we're not running at all. Checkpoints based on log
|
||||
* size also require logging be enabled.
|
||||
*/
|
||||
if (conn->ckpt_usecs != 0 ||
|
||||
(conn->ckpt_logsize != 0 &&
|
||||
FLD_ISSET(conn->log_flags, WT_CONN_LOG_ENABLED))) {
|
||||
/* Checkpoints are incompatible with in-memory configuration */
|
||||
WT_ERR(__wt_config_gets(session, cfg, "in_memory", &cval));
|
||||
if (cval.val != 0)
|
||||
WT_ERR_MSG(session, EINVAL,
|
||||
"checkpoint configuration incompatible with "
|
||||
"in-memory configuration");
|
||||
|
||||
__wt_log_written_reset(session);
|
||||
|
||||
*startp = true;
|
||||
}
|
||||
|
||||
err: __wt_scr_free(session, &tmp);
|
||||
return (ret);
|
||||
}
|
||||
@@ -179,7 +178,16 @@ __wt_checkpoint_server_create(WT_SESSION_IMPL *session, const char *cfg[])
|
||||
conn = S2C(session);
|
||||
start = false;
|
||||
|
||||
/* If there is already a server running, shut it down. */
|
||||
/*
|
||||
* Stop any server that is already running. This means that each time
|
||||
* reconfigure is called we'll bounce the server even if there are no
|
||||
* configuration changes. This makes our life easier as the underlying
|
||||
* configuration routine doesn't have to worry about freeing objects
|
||||
* in the connection structure (it's guaranteed to always start with a
|
||||
* blank slate), and we don't have to worry about races where a running
|
||||
* server is reading configuration information that we're updating, and
|
||||
* it's not expected that reconfiguration will happen a lot.
|
||||
*/
|
||||
if (conn->ckpt_session != NULL)
|
||||
WT_RET(__wt_checkpoint_server_destroy(session));
|
||||
|
||||
|
||||
@@ -51,6 +51,25 @@ __logmgr_config(
|
||||
WT_CONNECTION_IMPL *conn;
|
||||
bool enabled;
|
||||
|
||||
/*
|
||||
* A note on reconfiguration: the standard "is this configuration string
|
||||
* allowed" checks should fail if reconfiguration has invalid strings,
|
||||
* for example, "log=(enabled)", or "statistics_log=(path=XXX)", because
|
||||
* the connection reconfiguration method doesn't allow those strings.
|
||||
* Additionally, the base configuration values during reconfiguration
|
||||
* are the currently configured values (so we don't revert to default
|
||||
* values when repeatedly reconfiguring), and configuration processing
|
||||
* of a currently set value should not change the currently set value.
|
||||
*
|
||||
* In this code path, log server reconfiguration does not stop/restart
|
||||
* the log server, so there's no point in re-evaluating configuration
|
||||
* strings that cannot be reconfigured, risking bugs in configuration
|
||||
* setup, and depending on evaluation of currently set values to always
|
||||
* result in the currently set value. Skip tests for any configuration
|
||||
* strings which don't make sense during reconfiguration, but don't
|
||||
* worry about error reporting because it should never happen.
|
||||
*/
|
||||
|
||||
conn = S2C(session);
|
||||
|
||||
WT_RET(__wt_config_gets(session, cfg, "log.enabled", &cval));
|
||||
@@ -62,6 +81,8 @@ __logmgr_config(
|
||||
*
|
||||
* If it is off and the user it turning it on, or it is on
|
||||
* and the user is turning it off, return an error.
|
||||
*
|
||||
* See above: should never happen.
|
||||
*/
|
||||
if (reconfig &&
|
||||
((enabled && !FLD_ISSET(conn->log_flags, WT_CONN_LOG_ENABLED)) ||
|
||||
@@ -83,6 +104,8 @@ __logmgr_config(
|
||||
* Setup a log path and compression even if logging is disabled in case
|
||||
* we are going to print a log. Only do this on creation. Once a
|
||||
* compressor or log path are set they cannot be changed.
|
||||
*
|
||||
* See above: should never happen.
|
||||
*/
|
||||
if (!reconfig) {
|
||||
conn->log_compressor = NULL;
|
||||
@@ -95,6 +118,7 @@ __logmgr_config(
|
||||
WT_RET(__wt_strndup(
|
||||
session, cval.str, cval.len, &conn->log_path));
|
||||
}
|
||||
|
||||
/* We are done if logging isn't enabled. */
|
||||
if (!*runp)
|
||||
return (0);
|
||||
@@ -103,13 +127,14 @@ __logmgr_config(
|
||||
if (cval.val != 0)
|
||||
FLD_SET(conn->log_flags, WT_CONN_LOG_ARCHIVE);
|
||||
|
||||
/*
|
||||
* The file size cannot be reconfigured. The amount of memory allocated
|
||||
* to the log slots may be based on the log file size at creation and we
|
||||
* don't want to re-allocate that memory while running.
|
||||
*
|
||||
* See above: should never happen.
|
||||
*/
|
||||
if (!reconfig) {
|
||||
/*
|
||||
* Ignore if the user tries to change the file size. The
|
||||
* amount of memory allocated to the log slots may be based
|
||||
* on the log file size at creation and we don't want to
|
||||
* re-allocate that memory while running.
|
||||
*/
|
||||
WT_RET(__wt_config_gets(session, cfg, "log.file_max", &cval));
|
||||
conn->log_file_max = (wt_off_t)cval.val;
|
||||
WT_STAT_FAST_CONN_SET(session,
|
||||
@@ -125,12 +150,17 @@ __logmgr_config(
|
||||
conn->log_prealloc = 1;
|
||||
|
||||
/*
|
||||
* Note that it is meaningless to reconfigure this value during
|
||||
* runtime. It only matters on create before recovery runs.
|
||||
* Note it's meaningless to reconfigure this value during runtime, it
|
||||
* only matters on create before recovery runs.
|
||||
*
|
||||
* See above: should never happen.
|
||||
*/
|
||||
WT_RET(__wt_config_gets_def(session, cfg, "log.recover", 0, &cval));
|
||||
if (cval.len != 0 && WT_STRING_MATCH("error", cval.str, cval.len))
|
||||
FLD_SET(conn->log_flags, WT_CONN_LOG_RECOVER_ERR);
|
||||
if (!reconfig) {
|
||||
WT_RET(__wt_config_gets_def(
|
||||
session, cfg, "log.recover", 0, &cval));
|
||||
if (WT_STRING_MATCH("error", cval.str, cval.len))
|
||||
FLD_SET(conn->log_flags, WT_CONN_LOG_RECOVER_ERR);
|
||||
}
|
||||
|
||||
WT_RET(__wt_config_gets(session, cfg, "log.zero_fill", &cval));
|
||||
if (cval.val != 0) {
|
||||
|
||||
@@ -35,6 +35,31 @@ __stat_sources_free(WT_SESSION_IMPL *session, char ***sources)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* __stat_config_discard --
|
||||
* Discard all statistics-log configuration.
|
||||
*/
|
||||
static int
|
||||
__stat_config_discard(WT_SESSION_IMPL *session)
|
||||
{
|
||||
WT_CONNECTION_IMPL *conn;
|
||||
WT_DECL_RET;
|
||||
|
||||
conn = S2C(session);
|
||||
|
||||
/*
|
||||
* Discard all statistics-log configuration information, called when
|
||||
* reconfiguring or destroying the statistics logging setup,
|
||||
*/
|
||||
__wt_free(session, conn->stat_format);
|
||||
ret = __wt_fclose(session, &conn->stat_fs);
|
||||
__wt_free(session, conn->stat_path);
|
||||
__stat_sources_free(session, &conn->stat_sources);
|
||||
conn->stat_stamp = NULL;
|
||||
conn->stat_usecs = 0;
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* __wt_conn_stat_init --
|
||||
* Initialize the per-connection statistics.
|
||||
@@ -73,20 +98,37 @@ __statlog_config(WT_SESSION_IMPL *session, const char **cfg, bool *runp)
|
||||
WT_CONFIG objectconf;
|
||||
WT_CONFIG_ITEM cval, k, v;
|
||||
WT_CONNECTION_IMPL *conn;
|
||||
WT_DECL_ITEM(tmp);
|
||||
WT_DECL_RET;
|
||||
int cnt;
|
||||
char **sources;
|
||||
|
||||
/*
|
||||
* A note on reconfiguration: the standard "is this configuration string
|
||||
* allowed" checks should fail if reconfiguration has invalid strings,
|
||||
* for example, "log=(enabled)", or "statistics_log=(path=XXX)", because
|
||||
* the connection reconfiguration method doesn't allow those strings.
|
||||
* Additionally, the base configuration values during reconfiguration
|
||||
* are the currently configured values (so we don't revert to default
|
||||
* values when repeatedly reconfiguring), and configuration processing
|
||||
* of a currently set value should not change the currently set value.
|
||||
*
|
||||
* In this code path, a previous statistics log server reconfiguration
|
||||
* may have stopped the server (and we're about to restart it). Because
|
||||
* stopping the server discarded the configured information stored in
|
||||
* the connection structure, we have to re-evaluate all configuration
|
||||
* values, reconfiguration can't skip any of them.
|
||||
*/
|
||||
|
||||
conn = S2C(session);
|
||||
sources = NULL;
|
||||
|
||||
WT_RET(__wt_config_gets(session, cfg, "statistics_log.wait", &cval));
|
||||
/* Only start the server if wait time is non-zero */
|
||||
WT_RET(__wt_config_gets(session, cfg, "statistics_log.wait", &cval));
|
||||
*runp = cval.val != 0;
|
||||
conn->stat_usecs = (uint64_t)cval.val * WT_MILLION;
|
||||
|
||||
WT_RET(__wt_config_gets(
|
||||
session, cfg, "statistics_log.json", &cval));
|
||||
WT_RET(__wt_config_gets(session, cfg, "statistics_log.json", &cval));
|
||||
if (cval.val != 0)
|
||||
FLD_SET(conn->stat_flags, WT_CONN_STAT_JSON);
|
||||
|
||||
@@ -96,24 +138,30 @@ __statlog_config(WT_SESSION_IMPL *session, const char **cfg, bool *runp)
|
||||
FLD_SET(conn->stat_flags, WT_CONN_STAT_ON_CLOSE);
|
||||
|
||||
/*
|
||||
* Statistics logging configuration requires either a wait time or an
|
||||
* on-close setting.
|
||||
* We don't allow the log path to be reconfigured for security reasons.
|
||||
* (Applications passing input strings directly to reconfigure would
|
||||
* expose themselves to a potential security problem, the utility of
|
||||
* reconfiguring a statistics log path isn't worth the security risk.)
|
||||
*
|
||||
* See above for the details, but during reconfiguration we're loading
|
||||
* the path value from the saved configuration information, and it's
|
||||
* required during reconfiguration because we potentially stopped and
|
||||
* are restarting, the server.
|
||||
*/
|
||||
if (!*runp && !FLD_ISSET(conn->stat_flags, WT_CONN_STAT_ON_CLOSE))
|
||||
return (0);
|
||||
WT_RET(__wt_config_gets(session, cfg, "statistics_log.path", &cval));
|
||||
WT_ERR(__wt_scr_alloc(session, 0, &tmp));
|
||||
WT_ERR(__wt_buf_fmt(session,
|
||||
tmp, "%.*s/%s", (int)cval.len, cval.str, WT_STATLOG_FILENAME));
|
||||
WT_ERR(__wt_filename(session, tmp->data, &conn->stat_path));
|
||||
|
||||
/*
|
||||
* If any statistics logging is done, this must not be a read-only
|
||||
* connection.
|
||||
*/
|
||||
WT_RET(__wt_config_gets(session, cfg, "statistics_log.sources", &cval));
|
||||
WT_RET(__wt_config_subinit(session, &objectconf, &cval));
|
||||
WT_ERR(__wt_config_gets(session, cfg, "statistics_log.sources", &cval));
|
||||
WT_ERR(__wt_config_subinit(session, &objectconf, &cval));
|
||||
for (cnt = 0; (ret = __wt_config_next(&objectconf, &k, &v)) == 0; ++cnt)
|
||||
;
|
||||
WT_RET_NOTFOUND_OK(ret);
|
||||
WT_ERR_NOTFOUND_OK(ret);
|
||||
if (cnt != 0) {
|
||||
WT_RET(__wt_calloc_def(session, cnt + 1, &sources));
|
||||
WT_RET(__wt_config_subinit(session, &objectconf, &cval));
|
||||
WT_ERR(__wt_calloc_def(session, cnt + 1, &sources));
|
||||
WT_ERR(__wt_config_subinit(session, &objectconf, &cval));
|
||||
for (cnt = 0;
|
||||
(ret = __wt_config_next(&objectconf, &k, &v)) == 0; ++cnt) {
|
||||
/*
|
||||
@@ -138,29 +186,37 @@ __statlog_config(WT_SESSION_IMPL *session, const char **cfg, bool *runp)
|
||||
sources = NULL;
|
||||
}
|
||||
|
||||
WT_ERR(__wt_config_gets(session, cfg, "statistics_log.path", &cval));
|
||||
WT_ERR(__wt_nfilename(session, cval.str, cval.len, &conn->stat_path));
|
||||
|
||||
/*
|
||||
* When using JSON format, use the same timestamp format as MongoDB by
|
||||
* default.
|
||||
* default. This requires caution: the user might have set the timestamp
|
||||
* in a previous reconfigure call and we don't want to override that, so
|
||||
* compare the retrieved value with the default value to decide if we
|
||||
* should use the JSON default.
|
||||
*
|
||||
* (This still implies if the user explicitly sets the timestamp to the
|
||||
* default value, then sets the JSON flag in a separate reconfigure
|
||||
* call, or vice-versa, we will incorrectly switch to the JSON default
|
||||
* timestamp. But there's no way to detect that, and this is all a low
|
||||
* probability path.)
|
||||
*
|
||||
* !!!
|
||||
* Don't rewrite in the compressed "%FT%T.000Z" form, MSVC13 segfaults.
|
||||
*/
|
||||
if (FLD_ISSET(conn->stat_flags, WT_CONN_STAT_JSON)) {
|
||||
ret = __wt_config_gets(
|
||||
session, &cfg[1], "statistics_log.timestamp", &cval);
|
||||
if (ret == WT_NOTFOUND)
|
||||
WT_ERR(__wt_strdup(
|
||||
session, "%FT%T.000Z", &conn->stat_format));
|
||||
WT_ERR_NOTFOUND_OK(ret);
|
||||
}
|
||||
if (conn->stat_format == NULL) {
|
||||
WT_ERR(__wt_config_gets(
|
||||
session, cfg, "statistics_log.timestamp", &cval));
|
||||
#define WT_TIMESTAMP_DEFAULT "%b %d %H:%M:%S"
|
||||
#define WT_TIMESTAMP_JSON_DEFAULT "%Y-%m-%dT%H:%M:%S.000Z"
|
||||
WT_ERR(__wt_config_gets(
|
||||
session, cfg, "statistics_log.timestamp", &cval));
|
||||
if (FLD_ISSET(conn->stat_flags, WT_CONN_STAT_JSON) &&
|
||||
WT_STRING_MATCH(WT_TIMESTAMP_DEFAULT, cval.str, cval.len))
|
||||
WT_ERR(__wt_strdup(
|
||||
session, WT_TIMESTAMP_JSON_DEFAULT, &conn->stat_format));
|
||||
else
|
||||
WT_ERR(__wt_strndup(
|
||||
session, cval.str, cval.len, &conn->stat_format));
|
||||
}
|
||||
|
||||
err: __stat_sources_free(session, &sources);
|
||||
__wt_scr_free(session, &tmp);
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
@@ -373,7 +429,7 @@ __statlog_log_one(WT_SESSION_IMPL *session, WT_ITEM *path, WT_ITEM *tmp)
|
||||
if (path != NULL)
|
||||
(void)strcpy(path->mem, tmp->mem);
|
||||
WT_RET(__wt_fopen(session, tmp->mem,
|
||||
WT_OPEN_CREATE | WT_OPEN_FIXED, WT_STREAM_APPEND,
|
||||
WT_FS_OPEN_CREATE | WT_FS_OPEN_FIXED, WT_STREAM_APPEND,
|
||||
&log_stream));
|
||||
}
|
||||
conn->stat_fs = log_stream;
|
||||
@@ -538,14 +594,23 @@ __wt_statlog_create(WT_SESSION_IMPL *session, const char *cfg[])
|
||||
bool start;
|
||||
|
||||
conn = S2C(session);
|
||||
start = false;
|
||||
|
||||
/*
|
||||
* Stop any server that is already running. This means that each time
|
||||
* reconfigure is called we'll bounce the server even if there are no
|
||||
* configuration changes - but that makes our lives easier.
|
||||
* configuration changes. This makes our life easier as the underlying
|
||||
* configuration routine doesn't have to worry about freeing objects
|
||||
* in the connection structure (it's guaranteed to always start with a
|
||||
* blank slate), and we don't have to worry about races where a running
|
||||
* server is reading configuration information that we're updating, and
|
||||
* it's not expected that reconfiguration will happen a lot.
|
||||
*
|
||||
* If there's no server running, discard any configuration information
|
||||
* so we don't leak memory during reconfiguration.
|
||||
*/
|
||||
if (conn->stat_session != NULL)
|
||||
if (conn->stat_session == NULL)
|
||||
WT_RET(__stat_config_discard(session));
|
||||
else
|
||||
WT_RET(__wt_statlog_destroy(session, false));
|
||||
|
||||
WT_RET(__statlog_config(session, cfg, &start));
|
||||
@@ -568,38 +633,28 @@ __wt_statlog_destroy(WT_SESSION_IMPL *session, bool is_close)
|
||||
|
||||
conn = S2C(session);
|
||||
|
||||
/* Stop the server thread. */
|
||||
F_CLR(conn, WT_CONN_SERVER_STATISTICS);
|
||||
if (conn->stat_tid_set) {
|
||||
WT_TRET(__wt_cond_signal(session, conn->stat_cond));
|
||||
WT_TRET(__wt_thread_join(session, conn->stat_tid));
|
||||
conn->stat_tid_set = false;
|
||||
}
|
||||
WT_TRET(__wt_cond_destroy(session, &conn->stat_cond));
|
||||
|
||||
/* Log a set of statistics on shutdown if configured. */
|
||||
if (is_close)
|
||||
WT_TRET(__wt_statlog_log_one(session));
|
||||
|
||||
WT_TRET(__wt_cond_destroy(session, &conn->stat_cond));
|
||||
|
||||
__stat_sources_free(session, &conn->stat_sources);
|
||||
__wt_free(session, conn->stat_path);
|
||||
__wt_free(session, conn->stat_format);
|
||||
/* Discard all configuration information. */
|
||||
WT_TRET(__stat_config_discard(session));
|
||||
|
||||
/* Close the server thread's session. */
|
||||
if (conn->stat_session != NULL) {
|
||||
wt_session = &conn->stat_session->iface;
|
||||
WT_TRET(wt_session->close(wt_session, NULL));
|
||||
conn->stat_session = NULL;
|
||||
}
|
||||
|
||||
/* Clear connection settings so reconfigure is reliable. */
|
||||
conn->stat_session = NULL;
|
||||
conn->stat_tid_set = false;
|
||||
conn->stat_format = NULL;
|
||||
WT_TRET(__wt_fclose(session, &conn->stat_fs));
|
||||
conn->stat_path = NULL;
|
||||
conn->stat_sources = NULL;
|
||||
conn->stat_stamp = NULL;
|
||||
conn->stat_usecs = 0;
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
@@ -235,7 +235,7 @@ __backup_start(
|
||||
* doesn't confuse restarting in the source database.
|
||||
*/
|
||||
WT_ERR(__wt_fopen(session, WT_BACKUP_TMP,
|
||||
WT_OPEN_CREATE, WT_STREAM_WRITE, &cb->bfs));
|
||||
WT_FS_OPEN_CREATE, WT_STREAM_WRITE, &cb->bfs));
|
||||
/*
|
||||
* If a list of targets was specified, work our way through them.
|
||||
* Else, generate a list of all database objects.
|
||||
@@ -261,7 +261,7 @@ __backup_start(
|
||||
*/
|
||||
dest = WT_INCREMENTAL_BACKUP;
|
||||
WT_ERR(__wt_fopen(session, WT_INCREMENTAL_SRC,
|
||||
WT_OPEN_CREATE, WT_STREAM_WRITE, &srcfs));
|
||||
WT_FS_OPEN_CREATE, WT_STREAM_WRITE, &srcfs));
|
||||
WT_ERR(__backup_list_append(
|
||||
session, cb, WT_INCREMENTAL_BACKUP));
|
||||
} else {
|
||||
@@ -287,7 +287,7 @@ err: /* Close the hot backup file. */
|
||||
WT_TRET(__backup_stop(session));
|
||||
} else {
|
||||
WT_ASSERT(session, dest != NULL);
|
||||
WT_TRET(__wt_fs_rename(session, WT_BACKUP_TMP, dest));
|
||||
WT_TRET(__wt_fs_rename(session, WT_BACKUP_TMP, dest, false));
|
||||
}
|
||||
|
||||
return (ret);
|
||||
@@ -443,10 +443,10 @@ __wt_backup_file_remove(WT_SESSION_IMPL *session)
|
||||
* always know we were a source directory while there's any chance of
|
||||
* an incremental backup file existing.
|
||||
*/
|
||||
WT_TRET(__wt_remove_if_exists(session, WT_BACKUP_TMP));
|
||||
WT_TRET(__wt_remove_if_exists(session, WT_INCREMENTAL_BACKUP));
|
||||
WT_TRET(__wt_remove_if_exists(session, WT_INCREMENTAL_SRC));
|
||||
WT_TRET(__wt_remove_if_exists(session, WT_METADATA_BACKUP));
|
||||
WT_TRET(__wt_remove_if_exists(session, WT_BACKUP_TMP, true));
|
||||
WT_TRET(__wt_remove_if_exists(session, WT_INCREMENTAL_BACKUP, true));
|
||||
WT_TRET(__wt_remove_if_exists(session, WT_INCREMENTAL_SRC, true));
|
||||
WT_TRET(__wt_remove_if_exists(session, WT_METADATA_BACKUP, true));
|
||||
return (ret);
|
||||
}
|
||||
|
||||
|
||||
@@ -2,10 +2,23 @@
|
||||
|
||||
@section directory_permissions Database directory permissions
|
||||
|
||||
All WiredTiger files are stored in the database home directory, and the
|
||||
WiredTiger database directory should have its permissions set to ensure
|
||||
database objects are not accessible to users without appropriate
|
||||
permissions. See @ref home for more information.
|
||||
By default, WiredTiger files are stored beneath the database home directory.
|
||||
The WiredTiger database directory should have its permissions set to ensure
|
||||
database objects are not accessible to users without appropriate permissions.
|
||||
See @ref home for more information.
|
||||
|
||||
@section absolute_path Absolute paths
|
||||
|
||||
WiredTiger prepends the name of the database home to file names which
|
||||
do not appear to be absolute paths. (The absolute path test is
|
||||
simplistic, matching a leading slash character on POSIX systems or a
|
||||
leading alphabetic character and colon on Windows.) No file path
|
||||
sanitization or validation is done by WiredTiger, for example, file
|
||||
paths may match universal naming conventions (UNC), or include \c "../"
|
||||
(dot dot slash) components.
|
||||
|
||||
Applications are responsible for validating user-supplied file paths as
|
||||
necessary to prevent directory traversal attacks.
|
||||
|
||||
@section file_permissions File permissions
|
||||
|
||||
|
||||
@@ -80,6 +80,7 @@ SCons
|
||||
Seward's
|
||||
SiH
|
||||
TXT
|
||||
UNC
|
||||
URIs
|
||||
WILLNEED
|
||||
WiredTiger
|
||||
@@ -368,6 +369,7 @@ php
|
||||
png
|
||||
posix
|
||||
pre
|
||||
prepends
|
||||
primary's
|
||||
printf
|
||||
printlog
|
||||
@@ -411,6 +413,7 @@ runtime
|
||||
rwlock
|
||||
sHQ
|
||||
sHq
|
||||
sanitization
|
||||
scalable
|
||||
scanf
|
||||
schemas
|
||||
|
||||
@@ -90,11 +90,20 @@ cursor.
|
||||
|
||||
@section statistics_log Statistics logging
|
||||
|
||||
WiredTiger will optionally log database statistics into a file when the
|
||||
WiredTiger will optionally log database statistics into files when the
|
||||
the ::wiredtiger_open \c statistics_log configuration is set.
|
||||
|
||||
The resulting statistics can be displayed using the \c wtstats visualization
|
||||
tool. For more information, see @ref_single wtstats.
|
||||
The log files are named \c WiredTiger.%%d.%%H, where \c %%d is replaced
|
||||
with the day of the month as a decimal number (01-31), and \c %%H
|
||||
is replaced by the hour (24-hour clock) as a decimal number (00-23).
|
||||
Each log file contains the statistics for the hour specified in its name.
|
||||
|
||||
The location of the log files may be changed with the \c statistics_log.path
|
||||
configuration string.
|
||||
|
||||
The resulting statistics can be displayed and interactively examined
|
||||
using the \c wtstats visualization tool. For more information, see
|
||||
@ref_single wtstats.
|
||||
|
||||
The following example logs statistics every 30 seconds:
|
||||
|
||||
@@ -120,7 +129,7 @@ Statistics for all underlying data sources of a particular type may be
|
||||
included by adding a partial data source URI to the \c statistics_log
|
||||
configuration string:
|
||||
|
||||
@snippet ex_all.c Statistics logging with all tables
|
||||
@snippet ex_all.c Statistics logging with a source type
|
||||
|
||||
When database statistics are logged, the database home will be the first
|
||||
space-separated entry for each record in the log file. For example:
|
||||
@@ -151,23 +160,9 @@ currently open in the database, nor will any statistics requiring the
|
||||
traversal of a tree (as if the \c statistics_fast configuration string
|
||||
were set).
|
||||
|
||||
The location of the log files may be changed with the \c statistics_log.path
|
||||
configuration string. The \c path value value may contain ISO C90 standard
|
||||
strftime conversion specifications. WiredTiger will not create non-existent
|
||||
directories in the path, they must exist before ::wiredtiger_open is called.
|
||||
|
||||
The following example logs statistics into files named with the month,
|
||||
day and year:
|
||||
|
||||
@snippet ex_all.c Statistics logging with path
|
||||
|
||||
A Python script that parses the default logging output and uses the
|
||||
<a href="http://www.gnuplot.info/">gnuplot</a>, utility to generate
|
||||
Portable Network Graphics (PNG) format graphs is included in the
|
||||
WiredTiger distribution in the file \c tools/statlog.py.
|
||||
|
||||
@m_if{c}
|
||||
To interactively examine statistics results, see @ref wtstats.
|
||||
@m_endif
|
||||
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,16 @@
|
||||
/*! @page upgrading Upgrading WiredTiger applications
|
||||
|
||||
@section version_281 Upgrading to Version 2.8.1
|
||||
<dl>
|
||||
<dt>Statistics logging path</dt>
|
||||
<dd>
|
||||
The statistics logging path configuration has been simplified to be only a
|
||||
path to a directory, and the file name component of the path may no longer
|
||||
be specified. Applications depending on the ability to set statistics log
|
||||
file names will require modifications.
|
||||
</dd>
|
||||
|
||||
</dl><hr>
|
||||
@section version_280 Upgrading to Version 2.8.0
|
||||
<dl>
|
||||
<dt>LSM metadata</dt>
|
||||
@@ -55,7 +66,6 @@ The WiredTiger public API used to define a structure that could encapsulate
|
||||
log sequence numbers. That structure is no longer exposed publicly.
|
||||
</dd>
|
||||
|
||||
<dt>
|
||||
</dl><hr>
|
||||
@section version_270 Upgrading to Version 2.7.0
|
||||
|
||||
|
||||
@@ -145,6 +145,18 @@ done: if (((inmem_split && ret == 0) || (forced_eviction && ret == EBUSY)) &&
|
||||
WT_TRET(__wt_evict_server_wake(session));
|
||||
}
|
||||
|
||||
/*
|
||||
* When application threads perform eviction, we don't want to cache
|
||||
* reconciliation structures.
|
||||
*/
|
||||
if (!F_ISSET(session, WT_SESSION_INTERNAL)) {
|
||||
if (session->block_manager_cleanup != NULL)
|
||||
WT_TRET(session->block_manager_cleanup(session));
|
||||
|
||||
if (session->reconcile_cleanup != NULL)
|
||||
WT_TRET(session->reconcile_cleanup(session));
|
||||
}
|
||||
|
||||
return (ret);
|
||||
}
|
||||
/*
|
||||
|
||||
@@ -314,6 +314,7 @@ struct __wt_connection_impl {
|
||||
uint32_t evict_workers; /* Number of eviction workers */
|
||||
WT_EVICT_WORKER *evict_workctx; /* Eviction worker context */
|
||||
|
||||
#define WT_STATLOG_FILENAME "WiredTigerStat.%d.%H"
|
||||
WT_SESSION_IMPL *stat_session; /* Statistics log session */
|
||||
wt_thread_t stat_tid; /* Statistics log thread */
|
||||
bool stat_tid_set; /* Statistics log thread set */
|
||||
|
||||
@@ -38,9 +38,6 @@ __cursor_pos_clear(WT_CURSOR_BTREE *cbt)
|
||||
cbt->ins_head = NULL;
|
||||
cbt->ins_stack[0] = NULL;
|
||||
|
||||
cbt->cip_saved = NULL;
|
||||
cbt->rip_saved = NULL;
|
||||
|
||||
F_CLR(cbt, WT_CBT_POSITION_MASK);
|
||||
}
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@ extern void __wt_block_extlist_free(WT_SESSION_IMPL *session, WT_EXTLIST *el);
|
||||
extern int __wt_block_map(WT_SESSION_IMPL *session, WT_BLOCK *block, void *mapped_regionp, size_t *lengthp, void *mapped_cookiep);
|
||||
extern int __wt_block_unmap(WT_SESSION_IMPL *session, WT_BLOCK *block, void *mapped_region, size_t length, void *mapped_cookie);
|
||||
extern int __wt_block_manager_open(WT_SESSION_IMPL *session, const char *filename, const char *cfg[], bool forced_salvage, bool readonly, uint32_t allocsize, WT_BM **bmp);
|
||||
extern int __wt_block_manager_drop(WT_SESSION_IMPL *session, const char *filename);
|
||||
extern int __wt_block_manager_drop( WT_SESSION_IMPL *session, const char *filename, bool durable);
|
||||
extern int __wt_block_manager_create( WT_SESSION_IMPL *session, const char *filename, uint32_t allocsize);
|
||||
extern void __wt_block_configure_first_fit(WT_BLOCK *block, bool on);
|
||||
extern int __wt_block_open(WT_SESSION_IMPL *session, const char *filename, const char *cfg[], bool forced_salvage, bool readonly, uint32_t allocsize, WT_BLOCK **blockp);
|
||||
@@ -485,8 +485,7 @@ extern int __wt_turtle_read(WT_SESSION_IMPL *session, const char *key, char **va
|
||||
extern int __wt_turtle_update(WT_SESSION_IMPL *session, const char *key, const char *value);
|
||||
extern int __wt_filename(WT_SESSION_IMPL *session, const char *name, char **path);
|
||||
extern int __wt_nfilename( WT_SESSION_IMPL *session, const char *name, size_t namelen, char **path);
|
||||
extern int __wt_remove_if_exists(WT_SESSION_IMPL *session, const char *name);
|
||||
extern int __wt_rename_and_sync_directory( WT_SESSION_IMPL *session, const char *from, const char *to);
|
||||
extern int __wt_remove_if_exists(WT_SESSION_IMPL *session, const char *name, bool durable);
|
||||
extern int __wt_copy_and_sync(WT_SESSION *wt_session, const char *from, const char *to);
|
||||
extern void __wt_abort(WT_SESSION_IMPL *session) WT_GCC_FUNC_DECL_ATTRIBUTE((noreturn));
|
||||
extern int __wt_calloc(WT_SESSION_IMPL *session, size_t number, size_t size, void *retp);
|
||||
@@ -500,7 +499,7 @@ extern int __wt_errno(void);
|
||||
extern const char *__wt_strerror(WT_SESSION_IMPL *session, int error, char *errbuf, size_t errlen);
|
||||
extern int __wt_ext_map_windows_error( WT_EXTENSION_API *wt_api, WT_SESSION *wt_session, uint32_t windows_error);
|
||||
extern bool __wt_handle_is_open(WT_SESSION_IMPL *session, const char *name);
|
||||
extern int __wt_open(WT_SESSION_IMPL *session, const char *name, WT_OPEN_FILE_TYPE file_type, u_int flags, WT_FH **fhp);
|
||||
extern int __wt_open(WT_SESSION_IMPL *session, const char *name, WT_FS_OPEN_FILE_TYPE file_type, u_int flags, WT_FH **fhp);
|
||||
extern int __wt_close(WT_SESSION_IMPL *session, WT_FH **fhp);
|
||||
extern int __wt_close_connection_close(WT_SESSION_IMPL *session);
|
||||
extern int __wt_os_inmemory(WT_SESSION_IMPL *session);
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
/*
|
||||
* __wt_fs_directory_list --
|
||||
* Get a list of files from a directory.
|
||||
* Return a list of files from a directory.
|
||||
*/
|
||||
static inline int
|
||||
__wt_fs_directory_list(WT_SESSION_IMPL *session,
|
||||
@@ -60,61 +60,6 @@ __wt_fs_directory_list_free(
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* __wt_fs_directory_sync --
|
||||
* Flush a directory to ensure file creation is durable.
|
||||
*/
|
||||
static inline int
|
||||
__wt_fs_directory_sync(WT_SESSION_IMPL *session, const char *name)
|
||||
{
|
||||
WT_DECL_RET;
|
||||
WT_FILE_SYSTEM *file_system;
|
||||
WT_SESSION *wt_session;
|
||||
char *copy, *dir;
|
||||
|
||||
WT_ASSERT(session, !F_ISSET(S2C(session), WT_CONN_READONLY));
|
||||
|
||||
WT_RET(__wt_verbose(
|
||||
session, WT_VERB_FILEOPS, "%s: directory-sync", name));
|
||||
|
||||
/*
|
||||
* POSIX 1003.1 does not require that fsync of a file handle ensures the
|
||||
* entry in the directory containing the file has also reached disk (and
|
||||
* there are historic Linux filesystems requiring it). If the underlying
|
||||
* filesystem method is set, do an explicit fsync on a file descriptor
|
||||
* for the directory to be sure.
|
||||
*
|
||||
* directory-sync is not a required call, no method means the call isn't
|
||||
* needed.
|
||||
*/
|
||||
file_system = S2C(session)->file_system;
|
||||
if (file_system->fs_directory_sync == NULL)
|
||||
return (0);
|
||||
|
||||
copy = NULL;
|
||||
if (name == NULL || strchr(name, '/') == NULL)
|
||||
name = S2C(session)->home;
|
||||
else {
|
||||
/*
|
||||
* File name construction should not return a path without any
|
||||
* slash separator, but caution isn't unreasonable.
|
||||
*/
|
||||
WT_RET(__wt_filename(session, name, ©));
|
||||
if ((dir = strrchr(copy, '/')) == NULL)
|
||||
name = S2C(session)->home;
|
||||
else {
|
||||
dir[1] = '\0';
|
||||
name = copy;
|
||||
}
|
||||
}
|
||||
|
||||
wt_session = (WT_SESSION *)session;
|
||||
ret = file_system->fs_directory_sync(file_system, wt_session, name);
|
||||
|
||||
__wt_free(session, copy);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* __wt_fs_exist --
|
||||
* Return if the file exists.
|
||||
@@ -141,10 +86,10 @@ __wt_fs_exist(WT_SESSION_IMPL *session, const char *name, bool *existp)
|
||||
|
||||
/*
|
||||
* __wt_fs_remove --
|
||||
* POSIX remove.
|
||||
* Remove the file.
|
||||
*/
|
||||
static inline int
|
||||
__wt_fs_remove(WT_SESSION_IMPL *session, const char *name)
|
||||
__wt_fs_remove(WT_SESSION_IMPL *session, const char *name, bool durable)
|
||||
{
|
||||
WT_DECL_RET;
|
||||
WT_FILE_SYSTEM *file_system;
|
||||
@@ -169,7 +114,8 @@ __wt_fs_remove(WT_SESSION_IMPL *session, const char *name)
|
||||
|
||||
file_system = S2C(session)->file_system;
|
||||
wt_session = (WT_SESSION *)session;
|
||||
ret = file_system->fs_remove(file_system, wt_session, path);
|
||||
ret = file_system->fs_remove(
|
||||
file_system, wt_session, path, durable ? WT_FS_DURABLE : 0);
|
||||
|
||||
__wt_free(session, path);
|
||||
return (ret);
|
||||
@@ -177,10 +123,11 @@ __wt_fs_remove(WT_SESSION_IMPL *session, const char *name)
|
||||
|
||||
/*
|
||||
* __wt_fs_rename --
|
||||
* POSIX rename.
|
||||
* Rename the file.
|
||||
*/
|
||||
static inline int
|
||||
__wt_fs_rename(WT_SESSION_IMPL *session, const char *from, const char *to)
|
||||
__wt_fs_rename(
|
||||
WT_SESSION_IMPL *session, const char *from, const char *to, bool durable)
|
||||
{
|
||||
WT_DECL_RET;
|
||||
WT_FILE_SYSTEM *file_system;
|
||||
@@ -211,8 +158,8 @@ __wt_fs_rename(WT_SESSION_IMPL *session, const char *from, const char *to)
|
||||
|
||||
file_system = S2C(session)->file_system;
|
||||
wt_session = (WT_SESSION *)session;
|
||||
ret = file_system->fs_rename(
|
||||
file_system, wt_session, from_path, to_path);
|
||||
ret = file_system->fs_rename(file_system,
|
||||
wt_session, from_path, to_path, durable ? WT_FS_DURABLE : 0);
|
||||
|
||||
err: __wt_free(session, from_path);
|
||||
__wt_free(session, to_path);
|
||||
@@ -221,7 +168,7 @@ err: __wt_free(session, from_path);
|
||||
|
||||
/*
|
||||
* __wt_fs_size --
|
||||
* Get the size of a file in bytes, by file name.
|
||||
* Return the size of a file in bytes, by file name.
|
||||
*/
|
||||
static inline int
|
||||
__wt_fs_size(WT_SESSION_IMPL *session, const char *name, wt_off_t *sizep)
|
||||
|
||||
@@ -93,5 +93,5 @@ __wt_sync_and_rename(WT_SESSION_IMPL *session,
|
||||
WT_TRET(__wt_fclose(session, &fstr));
|
||||
WT_RET(ret);
|
||||
|
||||
return (__wt_rename_and_sync_directory(session, from, to));
|
||||
return (__wt_fs_rename(session, from, to, true));
|
||||
}
|
||||
|
||||
@@ -98,6 +98,7 @@ struct __wt_txn_global {
|
||||
volatile uint32_t checkpoint_id; /* Checkpoint's session ID */
|
||||
volatile uint64_t checkpoint_gen;
|
||||
volatile uint64_t checkpoint_pinned;
|
||||
volatile uint64_t checkpoint_txnid; /* Checkpoint's txn ID */
|
||||
|
||||
/* Named snapshot state. */
|
||||
WT_RWLOCK *nsnap_rwlock;
|
||||
|
||||
@@ -1836,25 +1836,8 @@ struct __wt_connection {
|
||||
* configuration options defined below.}
|
||||
* @config{ archive, automatically archive
|
||||
* unneeded log files., a boolean flag; default \c true.}
|
||||
* @config{ compressor, configure a compressor
|
||||
* for log records. Permitted values are \c "none" or custom
|
||||
* compression engine name created with WT_CONNECTION::add_compressor.
|
||||
* If WiredTiger has builtin support for \c "snappy"\, \c "lz4" or \c
|
||||
* "zlib" compression\, these names are also available. See @ref
|
||||
* compression for more information., a string; default \c none.}
|
||||
* @config{ enabled, enable logging subsystem., a
|
||||
* boolean flag; default \c false.}
|
||||
* @config{ file_max, the maximum size of log
|
||||
* files., an integer between 100KB and 2GB; default \c 100MB.}
|
||||
* @config{ path, the path to a directory into
|
||||
* which the log files are written. If the value is not an absolute
|
||||
* path name\, the files are created relative to the database home., a
|
||||
* string; default \c ".".}
|
||||
* @config{ prealloc,
|
||||
* pre-allocate log files., a boolean flag; default \c true.}
|
||||
* @config{ recover, run recovery or error if
|
||||
* recovery needs to run after an unclean shutdown., a string\, chosen
|
||||
* from the following options: \c "error"\, \c "on"; default \c on.}
|
||||
* @config{ prealloc, pre-allocate log files., a
|
||||
* boolean flag; default \c true.}
|
||||
* @config{ zero_fill, manually write zeroes into
|
||||
* log files., a boolean flag; default \c false.}
|
||||
* @config{ ),,}
|
||||
@@ -1914,11 +1897,6 @@ struct __wt_connection {
|
||||
* statistics in JSON format., a boolean flag; default \c false.}
|
||||
* @config{ on_close, log statistics on database
|
||||
* close., a boolean flag; default \c false.}
|
||||
* @config{ path, the pathname to a file into
|
||||
* which the log records are written\, may contain ISO C standard
|
||||
* strftime conversion specifications. If the value is not an absolute
|
||||
* path name\, the file is created relative to the database home., a
|
||||
* string; default \c "WiredTigerStat.%d.%H".}
|
||||
* @config{ sources, if non-empty\, include
|
||||
* statistics for the list of data source URIs\, if they are open at the
|
||||
* time of the statistics logging. The list may include URIs matching a
|
||||
@@ -2343,9 +2321,10 @@ struct __wt_connection {
|
||||
* subsystem., a boolean flag; default \c false.}
|
||||
* @config{ file_max, the maximum size of log files., an
|
||||
* integer between 100KB and 2GB; default \c 100MB.}
|
||||
* @config{ path, the path to a directory into which the
|
||||
* log files are written. If the value is not an absolute path name\, the files
|
||||
* are created relative to the database home., a string; default \c ".".}
|
||||
* @config{ path, the name of a directory into which log
|
||||
* files are written. The directory must already exist. If the value is not an
|
||||
* absolute path\, the path is relative to the database home (see @ref
|
||||
* absolute_path for more information)., a string; default \c ".".}
|
||||
* @config{ prealloc, pre-allocate log files., a boolean
|
||||
* flag; default \c true.}
|
||||
* @config{ recover, run recovery
|
||||
@@ -2415,16 +2394,15 @@ struct __wt_connection {
|
||||
* boolean flag; default \c false.}
|
||||
* @config{ on_close,
|
||||
* log statistics on database close., a boolean flag; default \c false.}
|
||||
* @config{ path, the pathname to a file into which the
|
||||
* log records are written\, may contain ISO C standard strftime conversion
|
||||
* specifications. If the value is not an absolute path name\, the file is
|
||||
* created relative to the database home., a string; default \c
|
||||
* "WiredTigerStat.%d.%H".}
|
||||
* @config{ sources, if
|
||||
* non-empty\, include statistics for the list of data source URIs\, if they are
|
||||
* open at the time of the statistics logging. The list may include URIs
|
||||
* matching a single data source ("table:mytable")\, or a URI matching all data
|
||||
* sources of a particular type ("table:")., a list of strings; default empty.}
|
||||
* @config{ path, the name of a directory into which
|
||||
* statistics files are written. The directory must already exist. If the
|
||||
* value is not an absolute path\, the path is relative to the database home
|
||||
* (see @ref absolute_path for more information)., a string; default \c ".".}
|
||||
* @config{ sources, if non-empty\, include statistics
|
||||
* for the list of data source URIs\, if they are open at the time of the
|
||||
* statistics logging. The list may include URIs matching a single data source
|
||||
* ("table:mytable")\, or a URI matching all data sources of a particular type
|
||||
* ("table:")., a list of strings; default empty.}
|
||||
* @config{ timestamp, a timestamp prepended to each log
|
||||
* record\, may contain strftime conversion specifications\, when \c json is
|
||||
* configured\, defaults to \c "%FT%Y.000Z"., a string; default \c "%b %d
|
||||
@@ -3701,24 +3679,34 @@ struct __wt_extractor {
|
||||
#if !defined(SWIG)
|
||||
/*! WT_FILE_SYSTEM::open_file file types */
|
||||
typedef enum {
|
||||
WT_OPEN_FILE_TYPE_CHECKPOINT, /*!< open a data file checkpoint */
|
||||
WT_OPEN_FILE_TYPE_DATA, /*!< open a data file */
|
||||
WT_OPEN_FILE_TYPE_DIRECTORY, /*!< open a directory */
|
||||
WT_OPEN_FILE_TYPE_LOG, /*!< open a log file */
|
||||
WT_OPEN_FILE_TYPE_REGULAR /*!< open a regular file */
|
||||
} WT_OPEN_FILE_TYPE;
|
||||
WT_FS_OPEN_FILE_TYPE_CHECKPOINT,/*!< open a data file checkpoint */
|
||||
WT_FS_OPEN_FILE_TYPE_DATA, /*!< open a data file */
|
||||
WT_FS_OPEN_FILE_TYPE_DIRECTORY, /*!< open a directory */
|
||||
WT_FS_OPEN_FILE_TYPE_LOG, /*!< open a log file */
|
||||
WT_FS_OPEN_FILE_TYPE_REGULAR /*!< open a regular file */
|
||||
} WT_FS_OPEN_FILE_TYPE;
|
||||
|
||||
/*! WT_FILE_SYSTEM::open_file flags: create if does not exist */
|
||||
#define WT_OPEN_CREATE 0x001
|
||||
#define WT_FS_OPEN_CREATE 0x001
|
||||
/*! WT_FILE_SYSTEM::open_file flags: direct I/O requested */
|
||||
#define WT_OPEN_DIRECTIO 0x002
|
||||
/*! WT_FILE_SYSTEM::open_file flags: error if exclusive use not available */
|
||||
#define WT_OPEN_EXCLUSIVE 0x004
|
||||
#define WT_FS_OPEN_DIRECTIO 0x002
|
||||
/*! WT_FILE_SYSTEM::open_file flags: file creation must be durable */
|
||||
#define WT_FS_OPEN_DURABLE 0x004
|
||||
/*!
|
||||
* WT_FILE_SYSTEM::open_file flags: return EBUSY if exclusive use not available
|
||||
*/
|
||||
#define WT_FS_OPEN_EXCLUSIVE 0x008
|
||||
#ifndef DOXYGEN
|
||||
#define WT_OPEN_FIXED 0x008 /* Path not home relative (internal) */
|
||||
#define WT_FS_OPEN_FIXED 0x010 /* Path not home relative (internal) */
|
||||
#endif
|
||||
/*! WT_FILE_SYSTEM::open_file flags: open is read-only */
|
||||
#define WT_OPEN_READONLY 0x010
|
||||
#define WT_FS_OPEN_READONLY 0x020
|
||||
|
||||
/*!
|
||||
* WT_FILE_SYSTEM::remove or WT_FILE_SYSTEM::rename flags: the remove or rename
|
||||
* operation must be durable
|
||||
*/
|
||||
#define WT_FS_DURABLE 0x001
|
||||
|
||||
/*!
|
||||
* The interface implemented by applications to provide a custom file system
|
||||
@@ -3767,23 +3755,6 @@ struct __wt_file_system {
|
||||
int (*fs_directory_list_free)(WT_FILE_SYSTEM *file_system,
|
||||
WT_SESSION *session, char **dirlist, uint32_t count);
|
||||
|
||||
/*!
|
||||
* Flush the named directory.
|
||||
*
|
||||
* This method is not required for readonly file systems or file systems
|
||||
* where it is not necessary to flush a file's directory to ensure the
|
||||
* durability of file system operations, and should be set to NULL when
|
||||
* not required by the file system.
|
||||
*
|
||||
* @errors
|
||||
*
|
||||
* @param file_system the WT_FILE_SYSTEM
|
||||
* @param session the current WiredTiger session
|
||||
* @param directory the name of the directory
|
||||
*/
|
||||
int (*fs_directory_sync)(WT_FILE_SYSTEM *file_system,
|
||||
WT_SESSION *session, const char *directory);
|
||||
|
||||
/*!
|
||||
* Return if the named file system object exists.
|
||||
*
|
||||
@@ -3800,6 +3771,16 @@ struct __wt_file_system {
|
||||
/*!
|
||||
* Open a handle for a named file system object
|
||||
*
|
||||
* The method should return ENOENT if the file is not being created and
|
||||
* does not exist.
|
||||
*
|
||||
* The method should return EACCES if the file cannot be opened in the
|
||||
* requested mode (for example, a file opened for writing in a readonly
|
||||
* file system).
|
||||
*
|
||||
* The method should return EBUSY if ::WT_FS_OPEN_EXCLUSIVE is set and
|
||||
* the file is in use.
|
||||
*
|
||||
* @errors
|
||||
*
|
||||
* @param file_system the WT_FILE_SYSTEM
|
||||
@@ -3809,8 +3790,8 @@ struct __wt_file_system {
|
||||
* The file type is provided to allow optimization for different file
|
||||
* access patterns.
|
||||
* @param flags flags indicating how to open the file, one or more of
|
||||
* ::WT_OPEN_CREATE, ::WT_OPEN_DIRECTIO, ::WT_OPEN_EXCLUSIVE or
|
||||
* ::WT_OPEN_READONLY.
|
||||
* ::WT_FS_OPEN_CREATE, ::WT_FS_OPEN_DIRECTIO, ::WT_FS_OPEN_DURABLE,
|
||||
* ::WT_FS_OPEN_EXCLUSIVE or ::WT_FS_OPEN_READONLY.
|
||||
* @param[out] file_handlep the handle to the newly opened file. File
|
||||
* system implementations must allocate memory for the handle and
|
||||
* the WT_FILE_HANDLE::name field, and fill in the WT_FILE_HANDLE::
|
||||
@@ -3819,7 +3800,7 @@ struct __wt_file_system {
|
||||
* their own structure as a superset of a WT_FILE_HANDLE:: structure.
|
||||
*/
|
||||
int (*fs_open_file)(WT_FILE_SYSTEM *file_system, WT_SESSION *session,
|
||||
const char *name, WT_OPEN_FILE_TYPE file_type, uint32_t flags,
|
||||
const char *name, WT_FS_OPEN_FILE_TYPE file_type, uint32_t flags,
|
||||
WT_FILE_HANDLE **file_handlep);
|
||||
|
||||
/*!
|
||||
@@ -3833,9 +3814,11 @@ struct __wt_file_system {
|
||||
* @param file_system the WT_FILE_SYSTEM
|
||||
* @param session the current WiredTiger session
|
||||
* @param name the name of the file system object
|
||||
* @param durable if the operation requires durability
|
||||
* @param flags 0 or ::WT_FS_DURABLE
|
||||
*/
|
||||
int (*fs_remove)(
|
||||
WT_FILE_SYSTEM *file_system, WT_SESSION *session, const char *name);
|
||||
int (*fs_remove)(WT_FILE_SYSTEM *file_system,
|
||||
WT_SESSION *session, const char *name, uint32_t flags);
|
||||
|
||||
/*!
|
||||
* Rename a named file system object
|
||||
@@ -3849,9 +3832,10 @@ struct __wt_file_system {
|
||||
* @param session the current WiredTiger session
|
||||
* @param from the original name of the object
|
||||
* @param to the new name for the object
|
||||
* @param flags 0 or ::WT_FS_DURABLE
|
||||
*/
|
||||
int (*fs_rename)(WT_FILE_SYSTEM *file_system,
|
||||
WT_SESSION *session, const char *from, const char *to);
|
||||
int (*fs_rename)(WT_FILE_SYSTEM *file_system, WT_SESSION *session,
|
||||
const char *from, const char *to, uint32_t flags);
|
||||
|
||||
/*!
|
||||
* Return the size of a named file system object
|
||||
|
||||
@@ -683,7 +683,7 @@ __log_openfile(WT_SESSION_IMPL *session,
|
||||
WT_LOG_DESC *desc;
|
||||
WT_LOG_RECORD *logrec;
|
||||
uint32_t allocsize;
|
||||
u_int flags;
|
||||
u_int wtopen_flags;
|
||||
|
||||
conn = S2C(session);
|
||||
log = conn->log;
|
||||
@@ -695,13 +695,13 @@ __log_openfile(WT_SESSION_IMPL *session,
|
||||
WT_ERR(__log_filename(session, id, file_prefix, buf));
|
||||
WT_ERR(__wt_verbose(session, WT_VERB_LOG,
|
||||
"opening log %s", (const char *)buf->data));
|
||||
flags = 0;
|
||||
wtopen_flags = 0;
|
||||
if (ok_create)
|
||||
LF_SET(WT_OPEN_CREATE);
|
||||
FLD_SET(wtopen_flags, WT_FS_OPEN_CREATE);
|
||||
if (FLD_ISSET(conn->direct_io, WT_DIRECT_IO_LOG))
|
||||
LF_SET(WT_OPEN_DIRECTIO);
|
||||
FLD_SET(wtopen_flags, WT_FS_OPEN_DIRECTIO);
|
||||
WT_ERR(__wt_open(
|
||||
session, buf->data, WT_OPEN_FILE_TYPE_LOG, flags, fhp));
|
||||
session, buf->data, WT_FS_OPEN_FILE_TYPE_LOG, wtopen_flags, fhp));
|
||||
|
||||
/*
|
||||
* If we are not creating the log file but opening it for reading,
|
||||
@@ -773,7 +773,7 @@ __log_alloc_prealloc(WT_SESSION_IMPL *session, uint32_t to_num)
|
||||
* All file setup, writing the header and pre-allocation was done
|
||||
* before. We only need to rename it.
|
||||
*/
|
||||
WT_ERR(__wt_fs_rename(session, from_path->data, to_path->data));
|
||||
WT_ERR(__wt_fs_rename(session, from_path->data, to_path->data, false));
|
||||
|
||||
err: __wt_scr_free(session, &from_path);
|
||||
__wt_scr_free(session, &to_path);
|
||||
@@ -1058,7 +1058,7 @@ __wt_log_allocfile(
|
||||
/*
|
||||
* Rename it into place and make it available.
|
||||
*/
|
||||
WT_ERR(__wt_fs_rename(session, from_path->data, to_path->data));
|
||||
WT_ERR(__wt_fs_rename(session, from_path->data, to_path->data, false));
|
||||
|
||||
err: __wt_scr_free(session, &from_path);
|
||||
__wt_scr_free(session, &to_path);
|
||||
@@ -1081,7 +1081,7 @@ __wt_log_remove(WT_SESSION_IMPL *session,
|
||||
WT_ERR(__log_filename(session, lognum, file_prefix, path));
|
||||
WT_ERR(__wt_verbose(session, WT_VERB_LOG,
|
||||
"log_remove: remove log %s", (char *)path->data));
|
||||
WT_ERR(__wt_fs_remove(session, path->data));
|
||||
WT_ERR(__wt_fs_remove(session, path->data, false));
|
||||
err: __wt_scr_free(session, &path);
|
||||
return (ret);
|
||||
}
|
||||
@@ -1117,7 +1117,7 @@ __wt_log_open(WT_SESSION_IMPL *session)
|
||||
WT_RET(__wt_verbose(session, WT_VERB_LOG,
|
||||
"log_open: open fh to directory %s", conn->log_path));
|
||||
WT_RET(__wt_open(session, conn->log_path,
|
||||
WT_OPEN_FILE_TYPE_DIRECTORY, 0, &log->log_dir_fh));
|
||||
WT_FS_OPEN_FILE_TYPE_DIRECTORY, 0, &log->log_dir_fh));
|
||||
}
|
||||
|
||||
if (!F_ISSET(conn, WT_CONN_READONLY)) {
|
||||
|
||||
@@ -219,13 +219,20 @@ __clsm_enter(WT_CURSOR_LSM *clsm, bool reset, bool update)
|
||||
* transaction ID in each chunk: any transaction ID
|
||||
* that overlaps with our snapshot is a potential
|
||||
* conflict.
|
||||
*
|
||||
* Note that the global snap_min is correct here: it
|
||||
* tracks concurrent transactions excluding special
|
||||
* transactions such as checkpoint (which we can't
|
||||
* conflict with because checkpoint only writes the
|
||||
* metadata, which is not an LSM tree).
|
||||
*/
|
||||
clsm->nupdates = 1;
|
||||
if (txn->isolation == WT_ISO_SNAPSHOT &&
|
||||
F_ISSET(clsm, WT_CLSM_OPEN_SNAPSHOT)) {
|
||||
WT_ASSERT(session,
|
||||
F_ISSET(txn, WT_TXN_HAS_SNAPSHOT));
|
||||
snap_min = txn->snap_min;
|
||||
snap_min =
|
||||
WT_SESSION_TXN_STATE(session)->snap_min;
|
||||
for (switch_txnp =
|
||||
&clsm->switch_txn[clsm->nchunks - 2];
|
||||
clsm->nupdates < clsm->nchunks;
|
||||
|
||||
@@ -526,7 +526,7 @@ __lsm_drop_file(WT_SESSION_IMPL *session, const char *uri)
|
||||
ret = __wt_schema_drop(session, uri, drop_cfg));
|
||||
|
||||
if (ret == 0)
|
||||
ret = __wt_fs_remove(session, uri + strlen("file:"));
|
||||
ret = __wt_fs_remove(session, uri + strlen("file:"), false);
|
||||
WT_RET(__wt_verbose(session, WT_VERB_LSM, "Dropped %s", uri));
|
||||
|
||||
if (ret == EBUSY || ret == ENOENT)
|
||||
|
||||
@@ -141,7 +141,8 @@ __meta_track_apply(WT_SESSION_IMPL *session, WT_META_TRACK *trk)
|
||||
ret = bm->checkpoint_resolve(bm, session));
|
||||
break;
|
||||
case WT_ST_DROP_COMMIT:
|
||||
if ((ret = __wt_block_manager_drop(session, trk->a)) != 0)
|
||||
if ((ret =
|
||||
__wt_block_manager_drop(session, trk->a, false)) != 0)
|
||||
__wt_err(session, ret,
|
||||
"metadata remove dropped file %s", trk->a);
|
||||
break;
|
||||
@@ -188,13 +189,15 @@ __meta_track_unroll(WT_SESSION_IMPL *session, WT_META_TRACK *trk)
|
||||
* For removes, b is NULL.
|
||||
*/
|
||||
if (trk->a != NULL && trk->b != NULL &&
|
||||
(ret = __wt_rename_and_sync_directory(session,
|
||||
trk->b + strlen("file:"), trk->a + strlen("file:"))) != 0)
|
||||
(ret = __wt_fs_rename(session,
|
||||
trk->b + strlen("file:"), trk->a + strlen("file:"),
|
||||
true)) != 0)
|
||||
__wt_err(session, ret,
|
||||
"metadata unroll rename %s to %s", trk->b, trk->a);
|
||||
|
||||
if (trk->a == NULL && (ret =
|
||||
__wt_fs_remove(session, trk->b + strlen("file:"))) != 0)
|
||||
if (trk->a == NULL &&
|
||||
(ret = __wt_fs_remove(session,
|
||||
trk->b + strlen("file:"), false)) != 0)
|
||||
__wt_err(session, ret,
|
||||
"metadata unroll create %s", trk->b);
|
||||
|
||||
|
||||
@@ -158,7 +158,7 @@ __wt_turtle_init(WT_SESSION_IMPL *session)
|
||||
* Discard any turtle setup file left-over from previous runs. This
|
||||
* doesn't matter for correctness, it's just cleaning up random files.
|
||||
*/
|
||||
WT_RET(__wt_remove_if_exists(session, WT_METADATA_TURTLE_SET));
|
||||
WT_RET(__wt_remove_if_exists(session, WT_METADATA_TURTLE_SET, false));
|
||||
|
||||
/*
|
||||
* We could die after creating the turtle file and before creating the
|
||||
@@ -197,9 +197,10 @@ __wt_turtle_init(WT_SESSION_IMPL *session)
|
||||
"Both %s and %s exist; recreating metadata from "
|
||||
"backup",
|
||||
WT_METADATA_TURTLE, WT_METADATA_BACKUP));
|
||||
WT_RET(__wt_remove_if_exists(session, WT_METAFILE));
|
||||
WT_RET(
|
||||
__wt_remove_if_exists(session, WT_METAFILE, false));
|
||||
WT_RET(__wt_remove_if_exists(
|
||||
session, WT_METADATA_TURTLE));
|
||||
session, WT_METADATA_TURTLE, false));
|
||||
load = true;
|
||||
}
|
||||
} else
|
||||
@@ -305,7 +306,7 @@ __wt_turtle_update(WT_SESSION_IMPL *session, const char *key, const char *value)
|
||||
* every time.
|
||||
*/
|
||||
WT_RET(__wt_fopen(session, WT_METADATA_TURTLE_SET,
|
||||
WT_OPEN_CREATE | WT_OPEN_EXCLUSIVE, WT_STREAM_WRITE, &fs));
|
||||
WT_FS_OPEN_CREATE | WT_FS_OPEN_EXCLUSIVE, WT_STREAM_WRITE, &fs));
|
||||
|
||||
version = wiredtiger_version(&vmajor, &vminor, &vpatch);
|
||||
WT_ERR(__wt_fprintf(session, fs,
|
||||
@@ -320,7 +321,7 @@ __wt_turtle_update(WT_SESSION_IMPL *session, const char *key, const char *value)
|
||||
|
||||
/* Close any file handle left open, remove any temporary file. */
|
||||
err: WT_TRET(__wt_fclose(session, &fs));
|
||||
WT_TRET(__wt_remove_if_exists(session, WT_METADATA_TURTLE_SET));
|
||||
WT_TRET(__wt_remove_if_exists(session, WT_METADATA_TURTLE_SET, false));
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
@@ -56,54 +56,16 @@ __wt_nfilename(
|
||||
* Remove a file if it exists.
|
||||
*/
|
||||
int
|
||||
__wt_remove_if_exists(WT_SESSION_IMPL *session, const char *name)
|
||||
__wt_remove_if_exists(WT_SESSION_IMPL *session, const char *name, bool durable)
|
||||
{
|
||||
bool exist;
|
||||
|
||||
WT_RET(__wt_fs_exist(session, name, &exist));
|
||||
if (exist)
|
||||
WT_RET(__wt_fs_remove(session, name));
|
||||
WT_RET(__wt_fs_remove(session, name, durable));
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* __wt_rename_and_sync_directory --
|
||||
* Rename a file and sync the enclosing directory.
|
||||
*/
|
||||
int
|
||||
__wt_rename_and_sync_directory(
|
||||
WT_SESSION_IMPL *session, const char *from, const char *to)
|
||||
{
|
||||
const char *fp, *tp;
|
||||
bool same_directory;
|
||||
|
||||
/* Rename the source file to the target. */
|
||||
WT_RET(__wt_fs_rename(session, from, to));
|
||||
|
||||
/*
|
||||
* Flush the backing directory to guarantee the rename. My reading of
|
||||
* POSIX 1003.1 is there's no guarantee flushing only one of the from
|
||||
* or to directories, or flushing a common parent, is sufficient, and
|
||||
* even if POSIX were to make that guarantee, existing filesystems are
|
||||
* known to not provide the guarantee or only provide the guarantee
|
||||
* with specific mount options. Flush both of the from/to directories
|
||||
* until it's a performance problem.
|
||||
*/
|
||||
WT_RET(__wt_fs_directory_sync(session, from));
|
||||
|
||||
/*
|
||||
* In almost all cases, we're going to be renaming files in the same
|
||||
* directory, we can at least fast-path that.
|
||||
*/
|
||||
fp = strrchr(from, '/');
|
||||
tp = strrchr(to, '/');
|
||||
same_directory = (fp == NULL && tp == NULL) ||
|
||||
(fp != NULL && tp != NULL &&
|
||||
fp - from == tp - to && memcmp(from, to, (size_t)(fp - from)) == 0);
|
||||
|
||||
return (same_directory ? 0 : __wt_fs_directory_sync(session, to));
|
||||
}
|
||||
|
||||
/*
|
||||
* __wt_copy_and_sync --
|
||||
* Copy a file safely; here to support the wt utility.
|
||||
@@ -134,13 +96,13 @@ __wt_copy_and_sync(WT_SESSION *wt_session, const char *from, const char *to)
|
||||
WT_ERR(__wt_scr_alloc(session, 0, &tmp));
|
||||
WT_ERR(__wt_buf_fmt(session, tmp, "%s.copy", to));
|
||||
|
||||
WT_ERR(__wt_remove_if_exists(session, to));
|
||||
WT_ERR(__wt_remove_if_exists(session, tmp->data));
|
||||
WT_ERR(__wt_remove_if_exists(session, to, false));
|
||||
WT_ERR(__wt_remove_if_exists(session, tmp->data, false));
|
||||
|
||||
/* Open the from and temporary file handles. */
|
||||
WT_ERR(__wt_open(session, from, WT_OPEN_FILE_TYPE_REGULAR, 0, &ffh));
|
||||
WT_ERR(__wt_open(session, tmp->data, WT_OPEN_FILE_TYPE_REGULAR,
|
||||
WT_OPEN_CREATE | WT_OPEN_EXCLUSIVE, &tfh));
|
||||
WT_ERR(__wt_open(session, from, WT_FS_OPEN_FILE_TYPE_REGULAR, 0, &ffh));
|
||||
WT_ERR(__wt_open(session, tmp->data, WT_FS_OPEN_FILE_TYPE_REGULAR,
|
||||
WT_FS_OPEN_CREATE | WT_FS_OPEN_EXCLUSIVE, &tfh));
|
||||
|
||||
/*
|
||||
* Allocate a copy buffer. Don't use a scratch buffer, this thing is
|
||||
@@ -162,7 +124,7 @@ __wt_copy_and_sync(WT_SESSION *wt_session, const char *from, const char *to)
|
||||
WT_ERR(__wt_fsync(session, tfh, true));
|
||||
WT_ERR(__wt_close(session, &tfh));
|
||||
|
||||
ret = __wt_rename_and_sync_directory(session, tmp->data, to);
|
||||
ret = __wt_fs_rename(session, tmp->data, to, true);
|
||||
|
||||
err: WT_TRET(__wt_close(session, &ffh));
|
||||
WT_TRET(__wt_close(session, &tfh));
|
||||
|
||||
@@ -150,19 +150,19 @@ __open_verbose(
|
||||
*/
|
||||
|
||||
switch (file_type) {
|
||||
case WT_OPEN_FILE_TYPE_CHECKPOINT:
|
||||
case WT_FS_OPEN_FILE_TYPE_CHECKPOINT:
|
||||
file_type_tag = "checkpoint";
|
||||
break;
|
||||
case WT_OPEN_FILE_TYPE_DATA:
|
||||
case WT_FS_OPEN_FILE_TYPE_DATA:
|
||||
file_type_tag = "data";
|
||||
break;
|
||||
case WT_OPEN_FILE_TYPE_DIRECTORY:
|
||||
case WT_FS_OPEN_FILE_TYPE_DIRECTORY:
|
||||
file_type_tag = "directory";
|
||||
break;
|
||||
case WT_OPEN_FILE_TYPE_LOG:
|
||||
case WT_FS_OPEN_FILE_TYPE_LOG:
|
||||
file_type_tag = "log";
|
||||
break;
|
||||
case WT_OPEN_FILE_TYPE_REGULAR:
|
||||
case WT_FS_OPEN_FILE_TYPE_REGULAR:
|
||||
file_type_tag = "regular";
|
||||
break;
|
||||
default:
|
||||
@@ -172,18 +172,18 @@ __open_verbose(
|
||||
|
||||
WT_RET(__wt_scr_alloc(session, 0, &tmp));
|
||||
sep = " (";
|
||||
#define WT_OPEN_VERBOSE_FLAG(f, name) \
|
||||
#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_OPEN_VERBOSE_FLAG(WT_OPEN_CREATE, "create");
|
||||
WT_OPEN_VERBOSE_FLAG(WT_OPEN_DIRECTIO, "direct-IO");
|
||||
WT_OPEN_VERBOSE_FLAG(WT_OPEN_EXCLUSIVE, "exclusive");
|
||||
WT_OPEN_VERBOSE_FLAG(WT_OPEN_FIXED, "fixed");
|
||||
WT_OPEN_VERBOSE_FLAG(WT_OPEN_READONLY, "readonly");
|
||||
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, ")"));
|
||||
@@ -209,7 +209,7 @@ err: __wt_scr_free(session, &tmp);
|
||||
*/
|
||||
int
|
||||
__wt_open(WT_SESSION_IMPL *session,
|
||||
const char *name, WT_OPEN_FILE_TYPE file_type, u_int flags, WT_FH **fhp)
|
||||
const char *name, WT_FS_OPEN_FILE_TYPE file_type, u_int flags, WT_FH **fhp)
|
||||
{
|
||||
WT_CONNECTION_IMPL *conn;
|
||||
WT_DECL_RET;
|
||||
@@ -247,12 +247,12 @@ __wt_open(WT_SESSION_IMPL *session,
|
||||
if (F_ISSET(conn, WT_CONN_READONLY)) {
|
||||
lock_file = strcmp(name, WT_SINGLETHREAD) == 0;
|
||||
if (!lock_file)
|
||||
LF_SET(WT_OPEN_READONLY);
|
||||
WT_ASSERT(session, lock_file || !LF_ISSET(WT_OPEN_CREATE));
|
||||
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_OPEN_FIXED))
|
||||
if (!LF_ISSET(WT_FS_OPEN_FIXED))
|
||||
WT_ERR(__wt_filename(session, name, &path));
|
||||
|
||||
/* Call the underlying open function. */
|
||||
@@ -261,7 +261,7 @@ __wt_open(WT_SESSION_IMPL *session,
|
||||
open_called = true;
|
||||
|
||||
WT_ERR(__fhandle_method_finalize(
|
||||
session, fh->handle, LF_ISSET(WT_OPEN_READONLY)));
|
||||
session, fh->handle, LF_ISSET(WT_FS_OPEN_READONLY)));
|
||||
|
||||
/*
|
||||
* Repeat the check for a match: if there's no match, link our newly
|
||||
|
||||
@@ -188,14 +188,16 @@ __im_fs_exist(WT_FILE_SYSTEM *file_system,
|
||||
* POSIX remove.
|
||||
*/
|
||||
static int
|
||||
__im_fs_remove(
|
||||
WT_FILE_SYSTEM *file_system, WT_SESSION *wt_session, const char *name)
|
||||
__im_fs_remove(WT_FILE_SYSTEM *file_system,
|
||||
WT_SESSION *wt_session, const char *name, uint32_t flags)
|
||||
{
|
||||
WT_DECL_RET;
|
||||
WT_FILE_HANDLE_INMEM *im_fh;
|
||||
WT_FILE_SYSTEM_INMEM *im_fs;
|
||||
WT_SESSION_IMPL *session;
|
||||
|
||||
WT_UNUSED(flags);
|
||||
|
||||
im_fs = (WT_FILE_SYSTEM_INMEM *)file_system;
|
||||
session = (WT_SESSION_IMPL *)wt_session;
|
||||
|
||||
@@ -215,7 +217,7 @@ __im_fs_remove(
|
||||
*/
|
||||
static int
|
||||
__im_fs_rename(WT_FILE_SYSTEM *file_system,
|
||||
WT_SESSION *wt_session, const char *from, const char *to)
|
||||
WT_SESSION *wt_session, const char *from, const char *to, uint32_t flags)
|
||||
{
|
||||
WT_DECL_RET;
|
||||
WT_FILE_HANDLE_INMEM *im_fh;
|
||||
@@ -224,6 +226,8 @@ __im_fs_rename(WT_FILE_SYSTEM *file_system,
|
||||
uint64_t bucket;
|
||||
char *copy;
|
||||
|
||||
WT_UNUSED(flags);
|
||||
|
||||
im_fs = (WT_FILE_SYSTEM_INMEM *)file_system;
|
||||
session = (WT_SESSION_IMPL *)wt_session;
|
||||
|
||||
@@ -463,7 +467,7 @@ err: __wt_spin_unlock(session, &im_fs->lock);
|
||||
*/
|
||||
static int
|
||||
__im_file_open(WT_FILE_SYSTEM *file_system, WT_SESSION *wt_session,
|
||||
const char *name, WT_OPEN_FILE_TYPE file_type, uint32_t flags,
|
||||
const char *name, WT_FS_OPEN_FILE_TYPE file_type, uint32_t flags,
|
||||
WT_FILE_HANDLE **file_handlep)
|
||||
{
|
||||
WT_DECL_RET;
|
||||
|
||||
@@ -187,7 +187,7 @@ __wt_fopen(WT_SESSION_IMPL *session,
|
||||
fstr = NULL;
|
||||
|
||||
WT_RET(__wt_open(
|
||||
session, name, WT_OPEN_FILE_TYPE_REGULAR, open_flags, &fh));
|
||||
session, name, WT_FS_OPEN_FILE_TYPE_REGULAR, open_flags, &fh));
|
||||
|
||||
WT_ERR(__wt_calloc_one(session, &fstr));
|
||||
fstr->fh = fh;
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
|
||||
/*
|
||||
* __posix_sync --
|
||||
* Underlying support function to flush a file handle.
|
||||
* Underlying support function to flush a file descriptor.
|
||||
*/
|
||||
static int
|
||||
__posix_sync(
|
||||
@@ -77,33 +77,42 @@ __posix_sync(
|
||||
#ifdef __linux__
|
||||
/*
|
||||
* __posix_directory_sync --
|
||||
* Flush a directory to ensure file creation is durable.
|
||||
* Flush a directory to ensure file creation, remove or rename is durable.
|
||||
*/
|
||||
static int
|
||||
__posix_directory_sync(
|
||||
WT_FILE_SYSTEM *file_system, WT_SESSION *wt_session, const char *path)
|
||||
__posix_directory_sync(WT_SESSION_IMPL *session, const char *path)
|
||||
{
|
||||
WT_DECL_ITEM(tmp);
|
||||
WT_DECL_RET;
|
||||
WT_SESSION_IMPL *session;
|
||||
int fd, tret;
|
||||
char *dir;
|
||||
|
||||
WT_UNUSED(file_system);
|
||||
WT_RET(__wt_scr_alloc(session, 0, &tmp));
|
||||
WT_ERR(__wt_buf_setstr(session, tmp, path));
|
||||
|
||||
session = (WT_SESSION_IMPL *)wt_session;
|
||||
/*
|
||||
* This layer should never see a path that doesn't include a trailing
|
||||
* path separator, this code asserts that fact.
|
||||
*/
|
||||
dir = tmp->mem;
|
||||
strrchr(dir, '/')[1] = '\0';
|
||||
|
||||
fd = -1; /* -Wconditional-uninitialized */
|
||||
WT_SYSCALL_RETRY((
|
||||
(fd = open(path, O_RDONLY, 0444)) == -1 ? -1 : 0), ret);
|
||||
(fd = open(dir, O_RDONLY, 0444)) == -1 ? -1 : 0), ret);
|
||||
if (ret != 0)
|
||||
WT_RET_MSG(session, ret, "%s: directory-sync: open", path);
|
||||
WT_ERR_MSG(session, ret, "%s: directory-sync: open", dir);
|
||||
|
||||
ret = __posix_sync(session, fd, path, "directory-sync");
|
||||
ret = __posix_sync(session, fd, dir, "directory-sync");
|
||||
|
||||
WT_SYSCALL(close(fd), tret);
|
||||
if (tret != 0) {
|
||||
__wt_err(session, tret, "%s: directory-sync: close", path);
|
||||
__wt_err(session, tret, "%s: directory-sync: close", dir);
|
||||
if (ret == 0)
|
||||
ret = tret;
|
||||
}
|
||||
|
||||
err: __wt_scr_free(session, &tmp);
|
||||
return (ret);
|
||||
}
|
||||
#endif
|
||||
@@ -141,8 +150,8 @@ __posix_fs_exist(WT_FILE_SYSTEM *file_system,
|
||||
* Remove a file.
|
||||
*/
|
||||
static int
|
||||
__posix_fs_remove(
|
||||
WT_FILE_SYSTEM *file_system, WT_SESSION *wt_session, const char *name)
|
||||
__posix_fs_remove(WT_FILE_SYSTEM *file_system,
|
||||
WT_SESSION *wt_session, const char *name, uint32_t flags)
|
||||
{
|
||||
WT_DECL_RET;
|
||||
WT_SESSION_IMPL *session;
|
||||
@@ -159,9 +168,17 @@ __posix_fs_remove(
|
||||
* using unlink may be marginally safer.
|
||||
*/
|
||||
WT_SYSCALL(unlink(name), ret);
|
||||
if (ret == 0)
|
||||
if (ret != 0)
|
||||
WT_RET_MSG(session, ret, "%s: file-remove: unlink", name);
|
||||
|
||||
if (!LF_ISSET(WT_FS_DURABLE))
|
||||
return (0);
|
||||
WT_RET_MSG(session, ret, "%s: file-remove: unlink", name);
|
||||
|
||||
#ifdef __linux__
|
||||
/* Flush the backing directory to guarantee the remove. */
|
||||
WT_RET (__posix_directory_sync(session, name));
|
||||
#endif
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -170,7 +187,7 @@ __posix_fs_remove(
|
||||
*/
|
||||
static int
|
||||
__posix_fs_rename(WT_FILE_SYSTEM *file_system,
|
||||
WT_SESSION *wt_session, const char *from, const char *to)
|
||||
WT_SESSION *wt_session, const char *from, const char *to, uint32_t flags)
|
||||
{
|
||||
WT_DECL_RET;
|
||||
WT_SESSION_IMPL *session;
|
||||
@@ -187,9 +204,43 @@ __posix_fs_rename(WT_FILE_SYSTEM *file_system,
|
||||
* return (if errno is 0), but we've done the best we can.
|
||||
*/
|
||||
WT_SYSCALL(rename(from, to) != 0 ? -1 : 0, ret);
|
||||
if (ret == 0)
|
||||
if (ret != 0)
|
||||
WT_RET_MSG(
|
||||
session, ret, "%s to %s: file-rename: rename", from, to);
|
||||
|
||||
if (!LF_ISSET(WT_FS_DURABLE))
|
||||
return (0);
|
||||
WT_RET_MSG(session, ret, "%s to %s: file-rename: rename", from, to);
|
||||
#ifdef __linux__
|
||||
/*
|
||||
* Flush the backing directory to guarantee the rename. My reading of
|
||||
* POSIX 1003.1 is there's no guarantee flushing only one of the from
|
||||
* or to directories, or flushing a common parent, is sufficient, and
|
||||
* even if POSIX were to make that guarantee, existing filesystems are
|
||||
* known to not provide the guarantee or only provide the guarantee
|
||||
* with specific mount options. Flush both of the from/to directories
|
||||
* until it's a performance problem.
|
||||
*/
|
||||
WT_RET(__posix_directory_sync(session, from));
|
||||
|
||||
/*
|
||||
* In almost all cases, we're going to be renaming files in the same
|
||||
* directory, we can at least fast-path that.
|
||||
*/
|
||||
{
|
||||
bool same_directory;
|
||||
const char *fp, *tp;
|
||||
|
||||
fp = strrchr(from, '/');
|
||||
tp = strrchr(to, '/');
|
||||
same_directory = (fp == NULL && tp == NULL) ||
|
||||
(fp != NULL && tp != NULL &&
|
||||
fp - from == tp - to && memcmp(from, to, (size_t)(fp - from)) == 0);
|
||||
|
||||
if (!same_directory)
|
||||
WT_RET(__posix_directory_sync(session, to));
|
||||
}
|
||||
#endif
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -513,7 +564,7 @@ __posix_open_file_cloexec(WT_SESSION_IMPL *session, int fd, const char *name)
|
||||
*/
|
||||
static int
|
||||
__posix_open_file(WT_FILE_SYSTEM *file_system, WT_SESSION *wt_session,
|
||||
const char *name, WT_OPEN_FILE_TYPE file_type, uint32_t flags,
|
||||
const char *name, WT_FS_OPEN_FILE_TYPE file_type, uint32_t flags,
|
||||
WT_FILE_HANDLE **file_handlep)
|
||||
{
|
||||
WT_CONNECTION_IMPL *conn;
|
||||
@@ -536,7 +587,7 @@ __posix_open_file(WT_FILE_SYSTEM *file_system, WT_SESSION *wt_session,
|
||||
/* Set up error handling. */
|
||||
pfh->fd = -1;
|
||||
|
||||
if (file_type == WT_OPEN_FILE_TYPE_DIRECTORY) {
|
||||
if (file_type == WT_FS_OPEN_FILE_TYPE_DIRECTORY) {
|
||||
f = O_RDONLY;
|
||||
#ifdef O_CLOEXEC
|
||||
/*
|
||||
@@ -554,10 +605,10 @@ __posix_open_file(WT_FILE_SYSTEM *file_system, WT_SESSION *wt_session,
|
||||
goto directory_open;
|
||||
}
|
||||
|
||||
f = LF_ISSET(WT_OPEN_READONLY) ? O_RDONLY : O_RDWR;
|
||||
if (LF_ISSET(WT_OPEN_CREATE)) {
|
||||
f = LF_ISSET(WT_FS_OPEN_READONLY) ? O_RDONLY : O_RDWR;
|
||||
if (LF_ISSET(WT_FS_OPEN_CREATE)) {
|
||||
f |= O_CREAT;
|
||||
if (LF_ISSET(WT_OPEN_EXCLUSIVE))
|
||||
if (LF_ISSET(WT_FS_OPEN_EXCLUSIVE))
|
||||
f |= O_EXCL;
|
||||
mode = 0666;
|
||||
} else
|
||||
@@ -577,7 +628,7 @@ __posix_open_file(WT_FILE_SYSTEM *file_system, WT_SESSION *wt_session,
|
||||
#endif
|
||||
#ifdef O_DIRECT
|
||||
/* Direct I/O. */
|
||||
if (LF_ISSET(WT_OPEN_DIRECTIO)) {
|
||||
if (LF_ISSET(WT_FS_OPEN_DIRECTIO)) {
|
||||
f |= O_DIRECT;
|
||||
pfh->direct_io = true;
|
||||
} else
|
||||
@@ -585,11 +636,11 @@ __posix_open_file(WT_FILE_SYSTEM *file_system, WT_SESSION *wt_session,
|
||||
#endif
|
||||
#ifdef O_NOATIME
|
||||
/* Avoid updating metadata for read-only workloads. */
|
||||
if (file_type == WT_OPEN_FILE_TYPE_DATA)
|
||||
if (file_type == WT_FS_OPEN_FILE_TYPE_DATA)
|
||||
f |= O_NOATIME;
|
||||
#endif
|
||||
|
||||
if (file_type == WT_OPEN_FILE_TYPE_LOG &&
|
||||
if (file_type == WT_FS_OPEN_FILE_TYPE_LOG &&
|
||||
FLD_ISSET(conn->txn_logsync, WT_LOG_DSYNC)) {
|
||||
#ifdef O_DSYNC
|
||||
f |= O_DSYNC;
|
||||
@@ -601,6 +652,7 @@ __posix_open_file(WT_FILE_SYSTEM *file_system, WT_SESSION *wt_session,
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Create/Open the file. */
|
||||
WT_SYSCALL_RETRY(((pfh->fd = open(name, f, mode)) == -1 ? -1 : 0), ret);
|
||||
if (ret != 0)
|
||||
WT_ERR_MSG(session, ret,
|
||||
@@ -608,6 +660,16 @@ __posix_open_file(WT_FILE_SYSTEM *file_system, WT_SESSION *wt_session,
|
||||
"%s: handle-open: open: failed with direct I/O configured, "
|
||||
"some filesystem types do not support direct I/O" :
|
||||
"%s: handle-open: open", name);
|
||||
|
||||
#ifdef __linux__
|
||||
/*
|
||||
* Durability: some filesystems require a directory sync to be confident
|
||||
* the file will appear.
|
||||
*/
|
||||
if (LF_ISSET(WT_FS_OPEN_DURABLE))
|
||||
WT_ERR(__posix_directory_sync(session, name));
|
||||
#endif
|
||||
|
||||
WT_ERR(__posix_open_file_cloexec(session, pfh->fd, name));
|
||||
|
||||
#if defined(HAVE_POSIX_FADVISE)
|
||||
@@ -616,7 +678,7 @@ __posix_open_file(WT_FILE_SYSTEM *file_system, WT_SESSION *wt_session,
|
||||
* Ignore fadvise when doing direct I/O, the kernel cache isn't
|
||||
* interesting.
|
||||
*/
|
||||
if (!pfh->direct_io && file_type == WT_OPEN_FILE_TYPE_DATA) {
|
||||
if (!pfh->direct_io && file_type == WT_FS_OPEN_FILE_TYPE_DATA) {
|
||||
WT_SYSCALL(
|
||||
posix_fadvise(pfh->fd, 0, 0, POSIX_FADV_RANDOM), ret);
|
||||
if (ret != 0)
|
||||
@@ -705,9 +767,6 @@ __wt_os_posix(WT_SESSION_IMPL *session)
|
||||
/* Initialize the POSIX jump table. */
|
||||
file_system->fs_directory_list = __wt_posix_directory_list;
|
||||
file_system->fs_directory_list_free = __wt_posix_directory_list_free;
|
||||
#ifdef __linux__
|
||||
file_system->fs_directory_sync = __posix_directory_sync;
|
||||
#endif
|
||||
file_system->fs_exist = __posix_fs_exist;
|
||||
file_system->fs_open_file = __posix_open_file;
|
||||
file_system->fs_remove = __posix_fs_remove;
|
||||
|
||||
@@ -36,13 +36,14 @@ __win_fs_exist(WT_FILE_SYSTEM *file_system,
|
||||
* Remove a file.
|
||||
*/
|
||||
static int
|
||||
__win_fs_remove(
|
||||
WT_FILE_SYSTEM *file_system, WT_SESSION *wt_session, const char *name)
|
||||
__win_fs_remove(WT_FILE_SYSTEM *file_system,
|
||||
WT_SESSION *wt_session, const char *name, uint32_t flags)
|
||||
{
|
||||
DWORD windows_error;
|
||||
WT_SESSION_IMPL *session;
|
||||
|
||||
WT_UNUSED(file_system);
|
||||
WT_UNUSED(flags);
|
||||
|
||||
session = (WT_SESSION_IMPL *)wt_session;
|
||||
|
||||
@@ -62,12 +63,13 @@ __win_fs_remove(
|
||||
*/
|
||||
static int
|
||||
__win_fs_rename(WT_FILE_SYSTEM *file_system,
|
||||
WT_SESSION *wt_session, const char *from, const char *to)
|
||||
WT_SESSION *wt_session, const char *from, const char *to, uint32_t flags)
|
||||
{
|
||||
DWORD windows_error;
|
||||
WT_SESSION_IMPL *session;
|
||||
|
||||
WT_UNUSED(file_system);
|
||||
WT_UNUSED(flags);
|
||||
|
||||
session = (WT_SESSION_IMPL *)wt_session;
|
||||
|
||||
@@ -426,7 +428,7 @@ __win_file_write(WT_FILE_HANDLE *file_handle,
|
||||
*/
|
||||
static int
|
||||
__win_open_file(WT_FILE_SYSTEM *file_system, WT_SESSION *wt_session,
|
||||
const char *name, WT_OPEN_FILE_TYPE file_type, uint32_t flags,
|
||||
const char *name, WT_FS_OPEN_FILE_TYPE file_type, uint32_t flags,
|
||||
WT_FILE_HANDLE **file_handlep)
|
||||
{
|
||||
DWORD dwCreationDisposition, windows_error;
|
||||
@@ -458,11 +460,11 @@ __win_open_file(WT_FILE_SYSTEM *file_system, WT_SESSION *wt_session,
|
||||
* require that functionality: create an empty WT_FH structure with
|
||||
* invalid handles.
|
||||
*/
|
||||
if (file_type == WT_OPEN_FILE_TYPE_DIRECTORY)
|
||||
if (file_type == WT_FS_OPEN_FILE_TYPE_DIRECTORY)
|
||||
goto directory_open;
|
||||
|
||||
desired_access = GENERIC_READ;
|
||||
if (!LF_ISSET(WT_OPEN_READONLY))
|
||||
if (!LF_ISSET(WT_FS_OPEN_READONLY))
|
||||
desired_access |= GENERIC_WRITE;
|
||||
|
||||
/*
|
||||
@@ -476,15 +478,15 @@ __win_open_file(WT_FILE_SYSTEM *file_system, WT_SESSION *wt_session,
|
||||
f = FILE_ATTRIBUTE_NORMAL;
|
||||
|
||||
dwCreationDisposition = 0;
|
||||
if (LF_ISSET(WT_OPEN_CREATE)) {
|
||||
if (LF_ISSET(WT_FS_OPEN_CREATE)) {
|
||||
dwCreationDisposition = CREATE_NEW;
|
||||
if (LF_ISSET(WT_OPEN_EXCLUSIVE))
|
||||
if (LF_ISSET(WT_FS_OPEN_EXCLUSIVE))
|
||||
dwCreationDisposition = CREATE_ALWAYS;
|
||||
} else
|
||||
dwCreationDisposition = OPEN_EXISTING;
|
||||
|
||||
/* Direct I/O. */
|
||||
if (LF_ISSET(WT_OPEN_DIRECTIO)) {
|
||||
if (LF_ISSET(WT_FS_OPEN_DIRECTIO)) {
|
||||
f |= FILE_FLAG_NO_BUFFERING;
|
||||
win_fh->direct_io = true;
|
||||
}
|
||||
@@ -493,19 +495,19 @@ __win_open_file(WT_FILE_SYSTEM *file_system, WT_SESSION *wt_session,
|
||||
if (FLD_ISSET(conn->write_through, file_type))
|
||||
f |= FILE_FLAG_WRITE_THROUGH;
|
||||
|
||||
if (file_type == WT_OPEN_FILE_TYPE_LOG &&
|
||||
if (file_type == WT_FS_OPEN_FILE_TYPE_LOG &&
|
||||
FLD_ISSET(conn->txn_logsync, WT_LOG_DSYNC))
|
||||
f |= FILE_FLAG_WRITE_THROUGH;
|
||||
|
||||
/* Disable read-ahead on trees: it slows down random read workloads. */
|
||||
if (file_type == WT_OPEN_FILE_TYPE_DATA)
|
||||
if (file_type == WT_FS_OPEN_FILE_TYPE_DATA)
|
||||
f |= FILE_FLAG_RANDOM_ACCESS;
|
||||
|
||||
win_fh->filehandle = CreateFileA(name, desired_access,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||
NULL, dwCreationDisposition, f, NULL);
|
||||
if (win_fh->filehandle == INVALID_HANDLE_VALUE) {
|
||||
if (LF_ISSET(WT_OPEN_CREATE) &&
|
||||
if (LF_ISSET(WT_FS_OPEN_CREATE) &&
|
||||
GetLastError() == ERROR_FILE_EXISTS)
|
||||
win_fh->filehandle = CreateFileA(name, desired_access,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||
@@ -528,7 +530,7 @@ __win_open_file(WT_FILE_SYSTEM *file_system, WT_SESSION *wt_session,
|
||||
* concurrently with reads on the file. Writes would also move the file
|
||||
* pointer.
|
||||
*/
|
||||
if (!LF_ISSET(WT_OPEN_READONLY)) {
|
||||
if (!LF_ISSET(WT_FS_OPEN_READONLY)) {
|
||||
win_fh->filehandle_secondary = CreateFileA(name, desired_access,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||
NULL, OPEN_EXISTING, f, NULL);
|
||||
|
||||
@@ -16,8 +16,30 @@ bool
|
||||
__wt_absolute_path(const char *path)
|
||||
{
|
||||
/*
|
||||
* Check for a drive name (for example, "D:"), allow both forward and
|
||||
* backward slashes.
|
||||
* https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247
|
||||
*
|
||||
* For Windows API functions that manipulate files, file names can often
|
||||
* be relative to the current directory, while some APIs require a fully
|
||||
* qualified path. A file name is relative to the current directory if
|
||||
* it does not begin with one of the following:
|
||||
*
|
||||
* -- A UNC name of any format, which always start with two backslash
|
||||
* characters ("\\").
|
||||
* -- A disk designator with a backslash, for example "C:\" or "d:\".
|
||||
* -- A single backslash, for example, "\directory" or "\file.txt". This
|
||||
* is also referred to as an absolute path.
|
||||
*
|
||||
* If a file name begins with only a disk designator but not the
|
||||
* backslash after the colon, it is interpreted as a relative path to
|
||||
* the current directory on the drive with the specified letter. Note
|
||||
* that the current directory may or may not be the root directory
|
||||
* depending on what it was set to during the most recent "change
|
||||
* directory" operation on that disk.
|
||||
*
|
||||
* -- "C:tmp.txt" refers to a file named "tmp.txt" in the current
|
||||
* directory on drive C.
|
||||
* -- "C:tempdir\tmp.txt" refers to a file in a subdirectory to the
|
||||
* current directory on drive C.
|
||||
*/
|
||||
if (strlen(path) >= 3 && __wt_isalpha(path[0]) && path[1] == ':')
|
||||
path += 2;
|
||||
|
||||
@@ -1135,8 +1135,18 @@ __rec_txn_read(WT_SESSION_IMPL *session, WT_RECONCILE *r,
|
||||
*/
|
||||
if (!skipped &&
|
||||
(F_ISSET(btree, WT_BTREE_LOOKASIDE) ||
|
||||
__wt_txn_visible_all(session, max_txn)))
|
||||
__wt_txn_visible_all(session, max_txn))) {
|
||||
/*
|
||||
* The checkpoint transaction is special. Make sure we never
|
||||
* write (metadata) updates from a checkpoint in a concurrent
|
||||
* session.
|
||||
*/
|
||||
WT_ASSERT(session, *updp == NULL ||
|
||||
(txnid = (*updp)->txnid) == WT_TXN_NONE ||
|
||||
txnid != S2C(session)->txn_global.checkpoint_txnid ||
|
||||
WT_SESSION_IS_CHECKPOINT(session));
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* In some cases, there had better not be skipped updates or updates not
|
||||
|
||||
@@ -64,7 +64,7 @@ __rename_file(
|
||||
WT_ERR(__wt_metadata_insert(session, newuri, oldvalue));
|
||||
|
||||
/* Rename the underlying file. */
|
||||
WT_ERR(__wt_fs_rename(session, filename, newfile));
|
||||
WT_ERR(__wt_fs_rename(session, filename, newfile, false));
|
||||
if (WT_META_TRACKING(session))
|
||||
WT_ERR(__wt_meta_track_fileop(session, uri, newuri));
|
||||
|
||||
|
||||
@@ -66,6 +66,11 @@ __wt_session_copy_values(WT_SESSION_IMPL *session)
|
||||
|
||||
TAILQ_FOREACH(cursor, &session->cursors, q)
|
||||
if (F_ISSET(cursor, WT_CURSTD_VALUE_INT)) {
|
||||
/* We have to do this with a transaction ID pinned. */
|
||||
WT_ASSERT(session,
|
||||
WT_SESSION_TXN_STATE(session)->snap_min !=
|
||||
WT_TXN_NONE);
|
||||
|
||||
F_CLR(cursor, WT_CURSTD_VALUE_INT);
|
||||
WT_RET(__wt_buf_set(session, &cursor->value,
|
||||
cursor->value.data, cursor->value.size));
|
||||
|
||||
@@ -124,6 +124,7 @@ __wt_txn_get_snapshot(WT_SESSION_IMPL *session)
|
||||
txn = &session->txn;
|
||||
txn_global = &conn->txn_global;
|
||||
txn_state = WT_SESSION_TXN_STATE(session);
|
||||
n = 0;
|
||||
|
||||
/*
|
||||
* Spin waiting for the lock: the sleeps in our blocking readlock
|
||||
@@ -137,20 +138,26 @@ __wt_txn_get_snapshot(WT_SESSION_IMPL *session)
|
||||
current_id = snap_min = txn_global->current;
|
||||
prev_oldest_id = txn_global->oldest_id;
|
||||
|
||||
/*
|
||||
* Include the checkpoint transaction, if one is running: we should
|
||||
* ignore any uncommitted changes the checkpoint has written to the
|
||||
* metadata. We don't have to keep the checkpoint's changes pinned so
|
||||
* don't including it in the published snap_min.
|
||||
*/
|
||||
if ((id = txn_global->checkpoint_txnid) != WT_TXN_NONE)
|
||||
txn->snapshot[n++] = id;
|
||||
|
||||
/* For pure read-only workloads, avoid scanning. */
|
||||
if (prev_oldest_id == current_id) {
|
||||
txn_state->snap_min = current_id;
|
||||
__txn_sort_snapshot(session, 0, current_id);
|
||||
|
||||
/* Check that the oldest ID has not moved in the meantime. */
|
||||
WT_ASSERT(session, prev_oldest_id == txn_global->oldest_id);
|
||||
WT_RET(__wt_readunlock(session, txn_global->scan_rwlock));
|
||||
return (0);
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Walk the array of concurrent transactions. */
|
||||
WT_ORDERED_READ(session_cnt, conn->session_cnt);
|
||||
for (i = n = 0, s = txn_global->states; i < session_cnt; i++, s++) {
|
||||
for (i = 0, s = txn_global->states; i < session_cnt; i++, s++) {
|
||||
/*
|
||||
* Build our snapshot of any concurrent transaction IDs.
|
||||
*
|
||||
@@ -178,8 +185,7 @@ __wt_txn_get_snapshot(WT_SESSION_IMPL *session)
|
||||
WT_ASSERT(session, prev_oldest_id == txn_global->oldest_id);
|
||||
txn_state->snap_min = snap_min;
|
||||
|
||||
WT_RET(__wt_readunlock(session, txn_global->scan_rwlock));
|
||||
|
||||
done: WT_RET(__wt_readunlock(session, txn_global->scan_rwlock));
|
||||
__txn_sort_snapshot(session, n, current_id);
|
||||
return (0);
|
||||
}
|
||||
@@ -433,18 +439,22 @@ __wt_txn_release(WT_SESSION_IMPL *session)
|
||||
WT_TXN_STATE *txn_state;
|
||||
|
||||
txn = &session->txn;
|
||||
WT_ASSERT(session, txn->mod_count == 0);
|
||||
txn->notify = NULL;
|
||||
|
||||
txn_global = &S2C(session)->txn_global;
|
||||
txn_state = WT_SESSION_TXN_STATE(session);
|
||||
|
||||
WT_ASSERT(session, txn->mod_count == 0);
|
||||
txn->notify = NULL;
|
||||
|
||||
/* Clear the transaction's ID from the global table. */
|
||||
if (WT_SESSION_IS_CHECKPOINT(session)) {
|
||||
WT_ASSERT(session, txn_state->id == WT_TXN_NONE);
|
||||
txn->id = WT_TXN_NONE;
|
||||
txn->id = txn_global->checkpoint_txnid = WT_TXN_NONE;
|
||||
|
||||
/* Clear the global checkpoint transaction IDs. */
|
||||
/*
|
||||
* Be extra careful to cleanup everything for checkpoints: once
|
||||
* the global checkpoint ID is cleared, we can no longer tell
|
||||
* if this session is doing a checkpoint.
|
||||
*/
|
||||
txn_global->checkpoint_id = 0;
|
||||
txn_global->checkpoint_pinned = WT_TXN_NONE;
|
||||
} else if (F_ISSET(txn, WT_TXN_HAS_ID)) {
|
||||
@@ -540,6 +550,16 @@ __wt_txn_commit(WT_SESSION_IMPL *session, const char *cfg[])
|
||||
WT_TRET(txn->notify->notify(txn->notify,
|
||||
(WT_SESSION *)session, txn->id, 1));
|
||||
|
||||
/*
|
||||
* We are about to release the snapshot: copy values into any
|
||||
* positioned cursors so they don't point to updates that could be
|
||||
* freed once we don't have a snapshot.
|
||||
*/
|
||||
if (session->ncursors > 0) {
|
||||
WT_DIAGNOSTIC_YIELD;
|
||||
WT_RET(__wt_session_copy_values(session));
|
||||
}
|
||||
|
||||
/* If we are logging, write a commit log record. */
|
||||
if (ret == 0 && txn->mod_count > 0 &&
|
||||
FLD_ISSET(conn->log_flags, WT_CONN_LOG_ENABLED) &&
|
||||
@@ -569,14 +589,6 @@ __wt_txn_commit(WT_SESSION_IMPL *session, const char *cfg[])
|
||||
__wt_txn_op_free(session, op);
|
||||
txn->mod_count = 0;
|
||||
|
||||
/*
|
||||
* We are about to release the snapshot: copy values into any
|
||||
* positioned cursors so they don't point to updates that could be
|
||||
* freed once we don't have a transaction ID pinned.
|
||||
*/
|
||||
if (session->ncursors > 0)
|
||||
WT_RET(__wt_session_copy_values(session));
|
||||
|
||||
__wt_txn_release(session);
|
||||
return (0);
|
||||
}
|
||||
|
||||
@@ -475,21 +475,22 @@ __txn_checkpoint(WT_SESSION_IMPL *session, const char *cfg[])
|
||||
WT_ERR(__wt_txn_id_check(session));
|
||||
|
||||
/*
|
||||
* Save the checkpoint session ID. We never do checkpoints in the
|
||||
* default session (with id zero).
|
||||
* Save the checkpoint session ID.
|
||||
*
|
||||
* We never do checkpoints in the default session (with id zero).
|
||||
*/
|
||||
WT_ASSERT(session, session->id != 0 && txn_global->checkpoint_id == 0);
|
||||
txn_global->checkpoint_id = session->id;
|
||||
|
||||
txn_global->checkpoint_pinned =
|
||||
WT_MIN(txn_state->id, txn_state->snap_min);
|
||||
|
||||
/*
|
||||
* We're about to clear the checkpoint transaction from the global
|
||||
* state table so the oldest ID can move forward. Make sure everything
|
||||
* we've done above is scheduled.
|
||||
* Remove the checkpoint transaction from the global table.
|
||||
*
|
||||
* This allows ordinary visibility checks to move forward because
|
||||
* checkpoints often take a long time and only write to the metadata.
|
||||
*/
|
||||
WT_FULL_BARRIER();
|
||||
WT_ERR(__wt_writelock(session, txn_global->scan_rwlock));
|
||||
txn_global->checkpoint_txnid = txn->id;
|
||||
txn_global->checkpoint_pinned = WT_MIN(txn->id, txn->snap_min);
|
||||
|
||||
/*
|
||||
* Sanity check that the oldest ID hasn't moved on before we have
|
||||
@@ -507,6 +508,7 @@ __txn_checkpoint(WT_SESSION_IMPL *session, const char *cfg[])
|
||||
* details).
|
||||
*/
|
||||
txn_state->id = txn_state->snap_min = WT_TXN_NONE;
|
||||
WT_ERR(__wt_writeunlock(session, txn_global->scan_rwlock));
|
||||
|
||||
/* Tell logging that we have started a database checkpoint. */
|
||||
if (full && logging)
|
||||
|
||||
@@ -95,19 +95,24 @@ class test_reconfig01(wttest.WiredTigerTestCase):
|
||||
self.conn.reconfigure("checkpoint=(wait=0,name=hi)")
|
||||
self.conn.reconfigure("checkpoint=(wait=5,name=hi)")
|
||||
|
||||
def test_reconfig_stat_log(self):
|
||||
# Statistics logging: reconfigure the things we can reconfigure.
|
||||
def test_reconfig_statistics_log_ok(self):
|
||||
self.conn.reconfigure("statistics=[all],statistics_log=(wait=0)")
|
||||
self.conn.reconfigure("statistics_log=(wait=0)")
|
||||
self.conn.reconfigure("statistics_log=(wait=2)")
|
||||
self.conn.reconfigure("statistics_log=(wait=2,json=true)")
|
||||
self.conn.reconfigure("statistics_log=(wait=0)")
|
||||
self.conn.reconfigure("statistics_log=(wait=2,on_close=true)")
|
||||
self.conn.reconfigure("statistics_log=(wait=0)")
|
||||
self.conn.reconfigure("statistics_log=(wait=2,sources=[lsm:])")
|
||||
self.conn.reconfigure("statistics_log=(wait=0)")
|
||||
self.conn.reconfigure("statistics_log=(wait=2,timestamp=\"t%b %d\")")
|
||||
self.conn.reconfigure("statistics_log=(wait=0)")
|
||||
self.conn.reconfigure("statistics_log=(wait=2,path=\"wts.%d.%H\")")
|
||||
self.conn.reconfigure("statistics_log=(wait=0)")
|
||||
self.conn.reconfigure(
|
||||
"statistics_log=(wait=2,sources=[lsm:],timestamp=\"%b\")")
|
||||
|
||||
# Statistics logging: reconfigure the things we can't reconfigure.
|
||||
def test_reconfig_statistics_log_fail(self):
|
||||
msg = '/unknown configuration key/'
|
||||
self.assertRaisesWithMessage(wiredtiger.WiredTigerError,
|
||||
lambda: self.conn.reconfigure("log=(path=foo)"), msg)
|
||||
|
||||
def test_file_manager(self):
|
||||
self.conn.reconfigure("file_manager=(close_scan_interval=3)")
|
||||
|
||||
@@ -41,24 +41,29 @@ class test_reconfig02(wttest.WiredTigerTestCase):
|
||||
self.conn_config = self.init_config
|
||||
return wttest.WiredTigerTestCase.setUpConnectionOpen(self, dir)
|
||||
|
||||
# Call reconfigure for zero filling a file. There is nothing
|
||||
# we can actually look for to confirm it did anything.
|
||||
# Also changing the log file size is a no-op, but should not fail.
|
||||
# Logging: reconfigure the things we can reconfigure.
|
||||
def test_reconfig02_simple(self):
|
||||
self.conn.reconfigure("log=(zero_fill=true)")
|
||||
self.conn.reconfigure("log=(file_max=1MB)")
|
||||
self.conn.reconfigure("log=(archive=false)")
|
||||
self.conn.reconfigure("log=(prealloc=false)")
|
||||
self.conn.reconfigure("log=(zero_fill=false)")
|
||||
|
||||
# Test that we get an error if we try to turn logging off.
|
||||
self.conn.reconfigure("log=(archive=true)")
|
||||
self.conn.reconfigure("log=(prealloc=true)")
|
||||
self.conn.reconfigure("log=(zero_fill=true)")
|
||||
|
||||
# Logging: reconfigure the things we can't reconfigure.
|
||||
def test_reconfig02_disable(self):
|
||||
msg = 'Invalid argument'
|
||||
gotException = False
|
||||
try:
|
||||
self.conn.reconfigure("log=(enabled=false)")
|
||||
except wiredtiger.WiredTigerError as e:
|
||||
gotException = True
|
||||
self.pr('got exception: ' + str(e))
|
||||
self.assertTrue(str(e).find(msg) >= 0)
|
||||
self.assertTrue(gotException)
|
||||
msg = '/unknown configuration key/'
|
||||
self.assertRaisesWithMessage(wiredtiger.WiredTigerError,
|
||||
lambda: self.conn.reconfigure("log=(enabled=true)"), msg)
|
||||
self.assertRaisesWithMessage(wiredtiger.WiredTigerError,
|
||||
lambda: self.conn.reconfigure("log=(compressor=foo)"), msg)
|
||||
self.assertRaisesWithMessage(wiredtiger.WiredTigerError,
|
||||
lambda: self.conn.reconfigure("log=(file_max=1MB)"), msg)
|
||||
self.assertRaisesWithMessage(wiredtiger.WiredTigerError,
|
||||
lambda: self.conn.reconfigure("log=(path=foo)"), msg)
|
||||
self.assertRaisesWithMessage(wiredtiger.WiredTigerError,
|
||||
lambda: self.conn.reconfigure("log=(recovery=true)"), msg)
|
||||
|
||||
# Logging starts on, but prealloc is off. Verify it is off.
|
||||
# Reconfigure it on and run again, making sure that log files
|
||||
|
||||
@@ -51,9 +51,10 @@ class test_stat_log01(wttest.WiredTigerTestCase):
|
||||
None, "create,statistics=(fast),statistics_log=(wait=1)")
|
||||
# Wait for the default interval, to ensure stats have been written.
|
||||
time.sleep(2)
|
||||
self.check_stats_file("WiredTigerStat")
|
||||
self.check_stats_file(".")
|
||||
|
||||
def test_stats_log_name(self):
|
||||
os.mkdir("foo")
|
||||
self.conn = self.wiredtiger_open(
|
||||
None, "create,statistics=(fast),statistics_log=(wait=1,path=foo)")
|
||||
# Wait for the default interval, to ensure stats have been written.
|
||||
@@ -66,21 +67,18 @@ class test_stat_log01(wttest.WiredTigerTestCase):
|
||||
# Wait for the default interval, to ensure stats have been written.
|
||||
time.sleep(2)
|
||||
self.close_conn()
|
||||
self.check_stats_file("WiredTigerStat")
|
||||
self.check_stats_file(".")
|
||||
|
||||
def test_stats_log_on_close(self):
|
||||
self.conn = self.wiredtiger_open(None,
|
||||
"create,statistics=(fast),statistics_log=(on_close=true)")
|
||||
# Close the connection to ensure the statistics get generated.
|
||||
self.close_conn()
|
||||
self.check_stats_file("WiredTigerStat")
|
||||
self.check_stats_file(".")
|
||||
|
||||
def check_stats_file(self, filename):
|
||||
if filename == "WiredTigerStat":
|
||||
files = glob.glob(filename + '.[0-9]*')
|
||||
self.assertTrue(files)
|
||||
else:
|
||||
self.assertTrue(os.path.isfile(filename))
|
||||
def check_stats_file(self, dir):
|
||||
files = glob.glob(dir + '/' + 'WiredTigerStat.[0-9]*')
|
||||
self.assertTrue(files)
|
||||
|
||||
if __name__ == '__main__':
|
||||
wttest.run()
|
||||
|
||||
Reference in New Issue
Block a user