summaryrefslogtreecommitdiff
path: root/src/third_party/wiredtiger/test/suite/test_tiered06.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/third_party/wiredtiger/test/suite/test_tiered06.py')
-rwxr-xr-xsrc/third_party/wiredtiger/test/suite/test_tiered06.py319
1 files changed, 226 insertions, 93 deletions
diff --git a/src/third_party/wiredtiger/test/suite/test_tiered06.py b/src/third_party/wiredtiger/test/suite/test_tiered06.py
index aba6b8a81b2..e0614cd8c1b 100755
--- a/src/third_party/wiredtiger/test/suite/test_tiered06.py
+++ b/src/third_party/wiredtiger/test/suite/test_tiered06.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python
#
-# Public Domain 2014-2020 MongoDB, Inc.
+# Public Domain 2014-present MongoDB, Inc.
# Public Domain 2008-2014 WiredTiger, Inc.
#
# This is free and unencumbered software released into the public domain.
@@ -27,7 +27,7 @@
# OTHER DEALINGS IN THE SOFTWARE.
import os, wiredtiger, wttest
-StorageSource = wiredtiger.StorageSource # easy access to constants
+FileSystem = wiredtiger.FileSystem # easy access to constants
# test_tiered06.py
# Test the local storage source.
@@ -64,58 +64,79 @@ class test_tiered06(wttest.WiredTigerTestCase):
local = self.get_local_storage_source()
os.mkdir("objects")
- location = local.ss_location_handle(session,
- 'cluster="cluster1",bucket="./objects",auth_token="Secret"')
+ fs = local.ss_customize_file_system(session, "./objects", "cluster1-", "Secret", None)
# The object doesn't exist yet.
- self.assertFalse(local.ss_exist(session, location, 'foobar'))
+ self.assertFalse(fs.fs_exist(session, 'foobar'))
- fh = local.ss_open_object(session, location, 'foobar', StorageSource.open_create)
+ fh = fs.fs_open_file(session, 'foobar', FileSystem.open_file_type_data, FileSystem.open_create)
+
+ # Just like a regular file system, the object exists now.
+ self.assertTrue(fs.fs_exist(session, 'foobar'))
outbytes = ('MORE THAN ENOUGH DATA\n'*100000).encode()
fh.fh_write(session, 0, outbytes)
- # The object doesn't even exist now.
- self.assertFalse(local.ss_exist(session, location, 'foobar'))
-
# The object exists after close
fh.close(session)
- self.assertTrue(local.ss_exist(session, location, 'foobar'))
+ self.assertTrue(fs.fs_exist(session, 'foobar'))
- fh = local.ss_open_object(session, location, 'foobar', StorageSource.open_readonly)
+ fh = fs.fs_open_file(session, 'foobar', FileSystem.open_file_type_data, FileSystem.open_readonly)
inbytes = bytes(1000000) # An empty buffer with a million zero bytes.
fh.fh_read(session, 0, inbytes) # read into the buffer
self.assertEquals(outbytes[0:1000000], inbytes)
- self.assertEquals(local.ss_size(session, location, 'foobar'), len(outbytes))
+ self.assertEquals(fs.fs_size(session, 'foobar'), len(outbytes))
self.assertEquals(fh.fh_size(session), len(outbytes))
fh.close(session)
# The fh_lock call doesn't do anything in the local store implementation.
- fh = local.ss_open_object(session, location, 'foobar', StorageSource.open_readonly)
+ fh = fs.fs_open_file(session, 'foobar', FileSystem.open_file_type_data, FileSystem.open_readonly)
fh.fh_lock(session, True)
fh.fh_lock(session, False)
fh.close(session)
- self.assertEquals(local.ss_location_list(session, location, '', 0), ['foobar'])
+ self.assertEquals(fs.fs_directory_list(session, '', ''), ['foobar'])
+
+ # Newly created objects are in the list.
+ fh = fs.fs_open_file(session, 'zzz', FileSystem.open_file_type_data, FileSystem.open_create)
+
+ # TODO: tiered: the newly created file should be visible, but it is not yet.
+ # self.assertEquals(sorted(fs.fs_directory_list(session, '', '')), ['foobar', 'zzz' ])
- # Make sure any new object is not in the list until it is closed.
- fh = local.ss_open_object(session, location, 'zzz', StorageSource.open_create)
- self.assertEquals(local.ss_location_list(session, location, '', 0), ['foobar'])
# Sync merely syncs to the local disk.
fh.fh_sync(session)
fh.close(session) # zero length
- self.assertEquals(sorted(local.ss_location_list(session, location, '', 0)),
- ['foobar', 'zzz'])
+ self.assertEquals(sorted(fs.fs_directory_list(session, '', '')), ['foobar', 'zzz' ])
+
+ # See that we can rename objects.
+ fs.fs_rename(session, 'zzz', 'yyy', 0)
+ self.assertEquals(sorted(fs.fs_directory_list(session, '', '')), ['foobar', 'yyy' ])
# See that we can remove objects.
- local.ss_remove(session, location, 'zzz', 0)
- self.assertEquals(local.ss_location_list(session, location, '', 0), ['foobar'])
+ fs.fs_remove(session, 'yyy', 0)
+ self.assertEquals(fs.fs_directory_list(session, '', ''), ['foobar'])
+
+ # TODO: tiered: flush tests disabled, as the interface
+ # for flushing will be changed.
+ return
# Flushing doesn't do anything that's visible.
- local.ss_flush(session, location, None, '')
- self.assertEquals(local.ss_location_list(session, location, '', 0), ['foobar'])
+ local.ss_flush(session, fs, None, '')
+ self.assertEquals(fs.fs_directory_list(session, '', ''), ['foobar'])
+
+ # Files that have been flushed cannot be manipulated.
+ with self.expectedStderrPattern('foobar: rename of flushed file not allowed'):
+ self.assertRaisesException(wiredtiger.WiredTigerError,
+ lambda: fs.fs_rename(session, 'foobar', 'barfoo', 0))
+ self.assertEquals(fs.fs_directory_list(session, '', ''), ['foobar'])
- location.close(session)
+ # Files that have been flushed cannot be manipulated through the custom file system.
+ with self.expectedStderrPattern('foobar: remove of flushed file not allowed'):
+ self.assertRaisesException(wiredtiger.WiredTigerError,
+ lambda: fs.fs_remove(session, 'foobar', 0))
+ self.assertEquals(fs.fs_directory_list(session, '', ''), ['foobar'])
+
+ fs.terminate(session)
def test_local_write_read(self):
# Write and read to a file non-sequentially.
@@ -124,14 +145,13 @@ class test_tiered06(wttest.WiredTigerTestCase):
local = self.get_local_storage_source()
os.mkdir("objects")
- location = local.ss_location_handle(session,
- 'cluster="cluster1",bucket="./objects",auth_token="Secret"')
+ fs = local.ss_customize_file_system(session, "./objects", "cluster1-", "Secret", None)
# We call these 4K chunks of data "blocks" for this test, but that doesn't
# necessarily relate to WT block sizing.
nblocks = 1000
block_size = 4096
- fh = local.ss_open_object(session, location, 'abc', StorageSource.open_create)
+ fh = fs.fs_open_file(session, 'abc', FileSystem.open_file_type_data, FileSystem.open_create)
# blocks filled with 'a', etc.
a_block = ('a' * block_size).encode()
@@ -153,7 +173,7 @@ class test_tiered06(wttest.WiredTigerTestCase):
fh.close(session)
in_block = bytes(block_size)
- fh = local.ss_open_object(session, location, 'abc', StorageSource.open_readonly)
+ fh = fs.fs_open_file(session, 'abc', FileSystem.open_file_type_data, FileSystem.open_readonly)
# Do some spot checks, reading non-sequentially
fh.fh_read(session, 500 * block_size, in_block) # divisible by 2, not 3
@@ -176,90 +196,203 @@ class test_tiered06(wttest.WiredTigerTestCase):
self.assertEquals(in_block, a_block)
fh.close(session)
- def create_in_loc(self, loc, objname):
+ def create_with_fs(self, fs, fname):
session = self.session
- fh = self.local.ss_open_object(session, loc, objname, StorageSource.open_create)
+ fh = fs.fs_open_file(session, fname, FileSystem.open_file_type_data, FileSystem.open_create)
fh.fh_write(session, 0, 'some stuff'.encode())
fh.close(session)
- def check(self, loc, prefix, limit, expect):
- # We don't require any sorted output for location lists,
+ objectdir1 = "./objects1"
+ objectdir2 = "./objects2"
+
+ cachedir1 = "./cache1"
+ cachedir2 = "./cache2"
+
+ def check(self, fs, prefix, expect):
+ # We don't require any sorted output for directory lists,
# so we'll sort before comparing.'
- got = sorted(self.local.ss_location_list(self.session, loc, prefix, limit))
+ got = sorted(fs.fs_directory_list(self.session, '', prefix))
expect = sorted(expect)
self.assertEquals(got, expect)
- def test_local_locations(self):
- # Test using various buckets, clusters
+ # Check that objects are "in the cloud" after a flush.
+ # Using the local storage module, they are actually going to be in either
+ # objectdir1 or objectdir2
+ def check_objects(self, expect1, expect2):
+ got = sorted(list(os.listdir(self.objectdir1)))
+ expect = sorted(expect1)
+ self.assertEquals(got, expect)
+ got = sorted(list(os.listdir(self.objectdir2)))
+ expect = sorted(expect2)
+ self.assertEquals(got, expect)
+
+ def test_local_file_systems(self):
+ # Test using various buckets, hosts
session = self.session
local = self.conn.get_storage_source('local_store')
self.local = local
- os.mkdir("objects1")
- os.mkdir("objects2")
-
- # Any of the activity that happens in the various locations
- # should be independent.
- location1 = local.ss_location_handle(session,
- 'cluster="cluster1",bucket="./objects1",auth_token="k1"')
- location2 = local.ss_location_handle(session,
- 'cluster="cluster1",bucket="./objects2",auth_token="k2"')
- location3 = local.ss_location_handle(session,
- 'cluster="cluster2",bucket="./objects1",auth_token="k3"')
- location4 = local.ss_location_handle(session,
- 'cluster="cluster2",bucket="./objects2",auth_token="k4"')
-
- # Create files in the locations with some name overlap
- self.create_in_loc(location1, 'alpaca')
- self.create_in_loc(location2, 'bear')
- self.create_in_loc(location3, 'crab')
- self.create_in_loc(location4, 'deer')
+ os.mkdir(self.objectdir1)
+ os.mkdir(self.objectdir2)
+ os.mkdir(self.cachedir1)
+ os.mkdir(self.cachedir2)
+ config1 = "cache_directory=" + self.cachedir1
+ config2 = "cache_directory=" + self.cachedir2
+ bad_config = "cache_directory=BAD"
+
+ # Create file system objects. First try some error cases.
+ errmsg = '/No such file or directory/'
+ self.assertRaisesWithMessage(wiredtiger.WiredTigerError,
+ lambda: local.ss_customize_file_system(
+ session, "./objects1", "pre1-", "k1", bad_config), errmsg)
+
+ self.assertRaisesWithMessage(wiredtiger.WiredTigerError,
+ lambda: local.ss_customize_file_system(
+ session, "./objects_BAD", "pre1-", "k1", config1), errmsg)
+
+ # Create an empty file, try to use it as a directory.
+ with open("some_file", "w"):
+ pass
+ errmsg = '/Invalid argument/'
+ self.assertRaisesWithMessage(wiredtiger.WiredTigerError,
+ lambda: local.ss_customize_file_system(
+ session, "some_file", "pre1-", "k1", config1), errmsg)
+
+ # Now create some file systems that should succeed.
+ # Use either different bucket directories or different prefixes,
+ # so activity that happens in the various file systems should be independent.
+ fs1 = local.ss_customize_file_system(session, "./objects1", "pre1-", "k1", config1)
+ fs2 = local.ss_customize_file_system(session, "./objects2", "pre1-", "k2", config2)
+ fs3 = local.ss_customize_file_system(session, "./objects1", "pre2-", "k3", config1)
+ fs4 = local.ss_customize_file_system(session, "./objects2", "pre2-", "k4", config2)
+
+ # Create files in the file systems with some name overlap
+ self.create_with_fs(fs1, 'alpaca')
+ self.create_with_fs(fs2, 'bear')
+ self.create_with_fs(fs3, 'crab')
+ self.create_with_fs(fs4, 'deer')
for a in ['beagle', 'bird', 'bison', 'bat']:
- self.create_in_loc(location1, a)
+ self.create_with_fs(fs1, a)
for a in ['bird', 'bison', 'bat', 'badger']:
- self.create_in_loc(location2, a)
+ self.create_with_fs(fs2, a)
for a in ['bison', 'bat', 'badger', 'baboon']:
- self.create_in_loc(location3, a)
+ self.create_with_fs(fs3, a)
for a in ['bat', 'badger', 'baboon', 'beagle']:
- self.create_in_loc(location4, a)
+ self.create_with_fs(fs4, a)
# Make sure we see the expected file names
- self.check(location1, '', 0, ['alpaca', 'beagle', 'bird', 'bison', 'bat'])
- self.check(location1, 'a', 0, ['alpaca'])
- self.check(location1, 'b', 0, ['beagle', 'bird', 'bison', 'bat'])
- self.check(location1, 'c', 0, [])
- self.check(location1, 'd', 0, [])
-
- self.check(location2, '', 0, ['bear', 'bird', 'bison', 'bat', 'badger'])
- self.check(location2, 'a', 0, [])
- self.check(location2, 'b', 0, ['bear', 'bird', 'bison', 'bat', 'badger'])
- self.check(location2, 'c', 0, [])
- self.check(location2, 'd', 0, [])
-
- self.check(location3, '', 0, ['crab', 'bison', 'bat', 'badger', 'baboon'])
- self.check(location3, 'a', 0, [])
- self.check(location3, 'b', 0, ['bison', 'bat', 'badger', 'baboon'])
- self.check(location3, 'c', 0, ['crab'])
- self.check(location3, 'd', 0, [])
-
- self.check(location4, '', 0, ['deer', 'bat', 'badger', 'baboon', 'beagle'])
- self.check(location4, 'a', 0, [])
- self.check(location4, 'b', 0, ['bat', 'badger', 'baboon', 'beagle'])
- self.check(location4, 'c', 0, [])
- self.check(location4, 'd', 0, ['deer'])
-
- # Flushing doesn't do anything that's visible, but calling it still exercises code paths.
- # At some point, we'll have statistics we can check.
+ self.check(fs1, '', ['alpaca', 'beagle', 'bird', 'bison', 'bat'])
+ self.check(fs1, 'a', ['alpaca'])
+ self.check(fs1, 'b', ['beagle', 'bird', 'bison', 'bat'])
+ self.check(fs1, 'c', [])
+ self.check(fs1, 'd', [])
+
+ self.check(fs2, '', ['bear', 'bird', 'bison', 'bat', 'badger'])
+ self.check(fs2, 'a', [])
+ self.check(fs2, 'b', ['bear', 'bird', 'bison', 'bat', 'badger'])
+ self.check(fs2, 'c', [])
+ self.check(fs2, 'd', [])
+
+ self.check(fs3, '', ['crab', 'bison', 'bat', 'badger', 'baboon'])
+ self.check(fs3, 'a', [])
+ self.check(fs3, 'b', ['bison', 'bat', 'badger', 'baboon'])
+ self.check(fs3, 'c', ['crab'])
+ self.check(fs3, 'd', [])
+
+ self.check(fs4, '', ['deer', 'bat', 'badger', 'baboon', 'beagle'])
+ self.check(fs4, 'a', [])
+ self.check(fs4, 'b', ['bat', 'badger', 'baboon', 'beagle'])
+ self.check(fs4, 'c', [])
+ self.check(fs4, 'd', ['deer'])
+
+ # Flushing copies files to one of the subdirectories:
+ # "./objects1" (for fs1 and fs3)
+ # "./objects2" (for fs2 and fs4)
#
- # For now, we can turn on the verbose config option for the local_store extension to verify.
- local.ss_flush(session, location4, None, '')
- local.ss_flush(session, location3, 'badger', '')
- local.ss_flush(session, location3, 'c', '') # make sure we don't flush prefixes
- local.ss_flush(session, location3, 'b', '') # or suffixes
- local.ss_flush(session, location3, 'crab', '')
- local.ss_flush(session, location3, 'crab', '') # should do nothing
- local.ss_flush(session, None, None, '') # flush everything else
- local.ss_flush(session, None, None, '') # should do nothing
+ # After every flush, we'll check that the right objects appear in the right directory.
+ # check_objects takes two lists: objects expected to be in ./objects1,
+ # and objects expected to be in ./objects2 .
+ self.check_objects([], [])
+
+ # TODO: tiered: flush tests disabled, as the interface
+ # for flushing will be changed.
+ enable_fs_flush_tests = False
+ if enable_fs_flush_tests:
+ local.ss_flush(session, fs4, None, '')
+ self.check_objects([], ['pre2-deer', 'pre2-bat', 'pre2-badger', 'pre2-baboon', 'pre2-beagle'])
+
+ local.ss_flush(session, fs3, 'badger', '')
+ self.check_objects(['pre2-badger'],
+ ['pre2-deer', 'pre2-bat', 'pre2-badger', 'pre2-baboon', 'pre2-beagle'])
+
+ #local.ss_flush(session, fs3, 'c', '') # make sure we don't flush prefixes
+ self.check_objects(['pre2-badger'],
+ ['pre2-deer', 'pre2-bat', 'pre2-badger', 'pre2-baboon', 'pre2-beagle'])
+
+ local.ss_flush(session, fs3, 'b', '') # or suffixes
+ self.check_objects(['pre2-badger'],
+ ['pre2-deer', 'pre2-bat', 'pre2-badger', 'pre2-baboon', 'pre2-beagle'])
+
+ local.ss_flush(session, fs3, 'crab', '')
+ self.check_objects(['pre2-crab', 'pre2-badger'],
+ ['pre2-deer', 'pre2-bat', 'pre2-badger', 'pre2-baboon', 'pre2-beagle'])
+
+ local.ss_flush(session, fs3, 'crab', '') # should do nothing
+ self.check_objects(['pre2-crab', 'pre2-badger'],
+ ['pre2-deer', 'pre2-bat', 'pre2-badger', 'pre2-baboon', 'pre2-beagle'])
+
+ local.ss_flush(session, None, None, '') # flush everything else
+ self.check_objects(['pre1-alpaca', 'pre1-beagle', 'pre1-bird', 'pre1-bison', 'pre1-bat',
+ 'pre2-crab', 'pre2-bison', 'pre2-bat', 'pre2-badger', 'pre2-baboon'],
+ ['pre1-bear', 'pre1-bird', 'pre1-bison', 'pre1-bat', 'pre1-badger',
+ 'pre2-deer', 'pre2-bat', 'pre2-badger', 'pre2-baboon', 'pre2-beagle'])
+
+ local.ss_flush(session, None, None, '') # should do nothing
+ self.check_objects(['pre1-alpaca', 'pre1-beagle', 'pre1-bird', 'pre1-bison', 'pre1-bat',
+ 'pre2-crab', 'pre2-bison', 'pre2-bat', 'pre2-badger', 'pre2-baboon'],
+ ['pre1-bear', 'pre1-bird', 'pre1-bison', 'pre1-bat', 'pre1-badger',
+ 'pre2-deer', 'pre2-bat', 'pre2-badger', 'pre2-baboon', 'pre2-beagle'])
+
+ self.create_with_fs(fs4, 'zebra') # should do nothing in the objects directories
+ self.create_with_fs(fs4, 'yeti') # should do nothing in the objects directories
+ self.check_objects(['pre1-alpaca', 'pre1-beagle', 'pre1-bird', 'pre1-bison', 'pre1-bat',
+ 'pre2-crab', 'pre2-bison', 'pre2-bat', 'pre2-badger', 'pre2-baboon'],
+ ['pre1-bear', 'pre1-bird', 'pre1-bison', 'pre1-bat', 'pre1-badger',
+ 'pre2-deer', 'pre2-bat', 'pre2-badger', 'pre2-baboon', 'pre2-beagle'])
+
+ # Try remove and rename, should be possible until we flush
+ self.check(fs4, '', ['deer', 'bat', 'badger', 'baboon', 'beagle', 'yeti', 'zebra'])
+ fs4.fs_remove(session, 'yeti', 0)
+ self.check(fs4, '', ['deer', 'bat', 'badger', 'baboon', 'beagle', 'zebra'])
+ fs4.fs_rename(session, 'zebra', 'okapi', 0)
+ self.check(fs4, '', ['deer', 'bat', 'badger', 'baboon', 'beagle', 'okapi'])
+ local.ss_flush(session, None, None, '')
+ self.check(fs4, '', ['deer', 'bat', 'badger', 'baboon', 'beagle', 'okapi'])
+ self.check_objects(['pre1-alpaca', 'pre1-beagle', 'pre1-bird', 'pre1-bison', 'pre1-bat',
+ 'pre2-crab', 'pre2-bison', 'pre2-bat', 'pre2-badger', 'pre2-baboon'],
+ ['pre1-bear', 'pre1-bird', 'pre1-bison', 'pre1-bat', 'pre1-badger',
+ 'pre2-deer', 'pre2-bat', 'pre2-badger', 'pre2-baboon', 'pre2-beagle',
+ 'pre2-okapi'])
+
+ errmsg = '/rename of flushed file not allowed/'
+ self.assertRaisesWithMessage(wiredtiger.WiredTigerError,
+ lambda: fs4.fs_rename(session, 'okapi', 'zebra', 0), errmsg)
+
+ # XXX
+ # At the moment, removal of flushed files is not allowed - as flushed files are immutable.
+ # We may need to explicitly evict flushed files from cache directory via the API, if so,
+ # the API to do that might be on the local store object, not the file system.
+ errmsg = '/remove of flushed file not allowed/'
+ self.assertRaisesWithMessage(wiredtiger.WiredTigerError,
+ lambda: fs4.fs_remove(session, 'okapi', 0), errmsg)
+
+ # No change since last time.
+ self.check(fs4, '', ['deer', 'bat', 'badger', 'baboon', 'beagle', 'okapi'])
+ self.check_objects(['pre1-alpaca', 'pre1-beagle', 'pre1-bird', 'pre1-bison', 'pre1-bat',
+ 'pre2-crab', 'pre2-bison', 'pre2-bat', 'pre2-badger', 'pre2-baboon'],
+ ['pre1-bear', 'pre1-bird', 'pre1-bison', 'pre1-bat', 'pre1-badger',
+ 'pre2-deer', 'pre2-bat', 'pre2-badger', 'pre2-baboon', 'pre2-beagle',
+ 'pre2-okapi'])
if __name__ == '__main__':
wttest.run()