Browse Source

Filesystem driver: add chunk size config option

At the moment, the filesystem driver uses a hardcoded 64 KB chunk
size, used when reading/writing image files.

This can be extremely inefficient, especially when file shares are
used.

For this reason, this change will make it configurable.

DocImpact

Change-Id: I1559c03308d36ecf9305c7a72ad658ecd1f2dc76
Closes-Bug: #1792869
tags/0.28.0
Lucian Petrut 8 months ago
parent
commit
ea1cad2bed

+ 28
- 14
glance_store/_drivers/filesystem.py View File

@@ -148,6 +148,23 @@ Possible values:
148 148
 Related options:
149 149
     * None
150 150
 
151
+"""),
152
+    cfg.IntOpt('filesystem_store_chunk_size',
153
+               default=64 * units.Ki,
154
+               min=1,
155
+               help="""
156
+Chunk size, in bytes.
157
+
158
+The chunk size used when reading or writing image files. Raising this value
159
+may improve the throughput but it may also slightly increase the memory usage
160
+when handling a large number of requests.
161
+
162
+Possible Values:
163
+    * Any positive integer value
164
+
165
+Related options:
166
+    * None
167
+
151 168
 """)]
152 169
 
153 170
 MULTI_FILESYSTEM_METADATA_SCHEMA = {
@@ -243,8 +260,6 @@ class Store(glance_store.driver.Store):
243 260
                      capabilities.BitMasks.WRITE_ACCESS |
244 261
                      capabilities.BitMasks.DRIVER_REUSABLE)
245 262
     OPTIONS = _FILESYSTEM_CONFIGS
246
-    READ_CHUNKSIZE = 64 * units.Ki
247
-    WRITE_CHUNKSIZE = READ_CHUNKSIZE
248 263
     FILESYSTEM_STORE_METADATA = None
249 264
 
250 265
     def get_schemes(self):
@@ -384,19 +399,18 @@ class Store(glance_store.driver.Store):
384 399
         itself, it should raise `exceptions.BadStoreConfiguration`
385 400
         """
386 401
         if self.backend_group:
387
-            fdir = getattr(
388
-                self.conf, self.backend_group).filesystem_store_datadir
389
-            fdirs = getattr(
390
-                self.conf, self.backend_group).filesystem_store_datadirs
391
-            fstore_perm = getattr(
392
-                self.conf, self.backend_group).filesystem_store_file_perm
393
-            meta_file = getattr(
394
-                self.conf, self.backend_group).filesystem_store_metadata_file
402
+            store_conf = getattr(self.conf, self.backend_group)
395 403
         else:
396
-            fdir = self.conf.glance_store.filesystem_store_datadir
397
-            fdirs = self.conf.glance_store.filesystem_store_datadirs
398
-            fstore_perm = self.conf.glance_store.filesystem_store_file_perm
399
-            meta_file = self.conf.glance_store.filesystem_store_metadata_file
404
+            store_conf = self.conf.glance_store
405
+
406
+        fdir = store_conf.filesystem_store_datadir
407
+        fdirs = store_conf.filesystem_store_datadirs
408
+        fstore_perm = store_conf.filesystem_store_file_perm
409
+        meta_file = store_conf.filesystem_store_metadata_file
410
+
411
+        self.chunk_size = store_conf.filesystem_store_chunk_size
412
+        self.READ_CHUNKSIZE = self.chunk_size
413
+        self.WRITE_CHUNKSIZE = self.READ_CHUNKSIZE
400 414
 
401 415
         if not (fdir or fdirs):
402 416
             reason = (_("Specify at least 'filesystem_store_datadir' or "

+ 16
- 8
glance_store/tests/unit/test_filesystem_store.py View File

@@ -43,21 +43,15 @@ class TestStore(base.StoreBaseTest,
43 43
     def setUp(self):
44 44
         """Establish a clean test environment."""
45 45
         super(TestStore, self).setUp()
46
-        self.orig_chunksize = filesystem.Store.READ_CHUNKSIZE
47
-        filesystem.Store.READ_CHUNKSIZE = 10
48 46
         self.store = filesystem.Store(self.conf)
49 47
         self.config(filesystem_store_datadir=self.test_dir,
48
+                    filesystem_store_chunk_size=10,
50 49
                     stores=['glance.store.filesystem.Store'],
51 50
                     group="glance_store")
52 51
         self.store.configure()
53 52
         self.register_store_schemes(self.store, 'file')
54 53
         self.hash_algo = 'sha256'
55 54
 
56
-    def tearDown(self):
57
-        """Clear the test environment."""
58
-        super(TestStore, self).tearDown()
59
-        filesystem.ChunkedFile.CHUNKSIZE = self.orig_chunksize
60
-
61 55
     def _create_metadata_json_file(self, metadata):
62 56
         expected_image_id = str(uuid.uuid4())
63 57
         jsonfilename = os.path.join(self.test_dir,
@@ -185,7 +179,10 @@ class TestStore(base.StoreBaseTest,
185 179
     def test_add_with_verifier(self):
186 180
         """Test that 'verifier.update' is called when verifier is provided."""
187 181
         verifier = mock.MagicMock(name='mock_verifier')
188
-        self.store.chunk_size = units.Ki
182
+        self.config(filesystem_store_chunk_size=units.Ki,
183
+                    group='glance_store')
184
+        self.store.configure()
185
+
189 186
         image_id = str(uuid.uuid4())
190 187
         file_size = units.Ki  # 1K
191 188
         file_contents = b"*" * file_size
@@ -741,3 +738,14 @@ class TestStore(base.StoreBaseTest,
741 738
         mode = os.stat(expected_location[len('file:/'):])[stat.ST_MODE]
742 739
         perm = int(str(self.conf.glance_store.filesystem_store_file_perm), 8)
743 740
         self.assertEqual(perm, stat.S_IMODE(mode))
741
+
742
+    def test_configure_add_chunk_size(self):
743
+        # This definitely won't be the default
744
+        chunk_size = units.Gi
745
+        self.config(filesystem_store_chunk_size=chunk_size,
746
+                    group="glance_store")
747
+        self.store.configure_add()
748
+
749
+        self.assertEqual(chunk_size, self.store.chunk_size)
750
+        self.assertEqual(chunk_size, self.store.READ_CHUNKSIZE)
751
+        self.assertEqual(chunk_size, self.store.WRITE_CHUNKSIZE)

+ 1
- 7
glance_store/tests/unit/test_multistore_filesystem.py View File

@@ -70,19 +70,13 @@ class TestMultiStore(base.MultiStoreBaseTest,
70 70
         self.test_dir = self.useFixture(fixtures.TempDir()).path
71 71
         self.addCleanup(self.conf.reset)
72 72
 
73
-        self.orig_chunksize = filesystem.Store.READ_CHUNKSIZE
74
-        filesystem.Store.READ_CHUNKSIZE = 10
75 73
         self.store = filesystem.Store(self.conf, backend='file1')
76 74
         self.config(filesystem_store_datadir=self.test_dir,
75
+                    filesystem_store_chunk_size=10,
77 76
                     group="file1")
78 77
         self.store.configure()
79 78
         self.register_store_backend_schemes(self.store, 'file', 'file1')
80 79
 
81
-    def tearDown(self):
82
-        """Clear the test environment."""
83
-        super(TestMultiStore, self).tearDown()
84
-        filesystem.ChunkedFile.CHUNKSIZE = self.orig_chunksize
85
-
86 80
     def _create_metadata_json_file(self, metadata):
87 81
         expected_image_id = str(uuid.uuid4())
88 82
         jsonfilename = os.path.join(self.test_dir,

+ 1
- 0
glance_store/tests/unit/test_opts.py View File

@@ -85,6 +85,7 @@ class OptsTestCase(base.StoreBaseTest):
85 85
             'cinder_volume_type',
86 86
             'default_swift_reference',
87 87
             'https_insecure',
88
+            'filesystem_store_chunk_size',
88 89
             'filesystem_store_datadir',
89 90
             'filesystem_store_datadirs',
90 91
             'filesystem_store_file_perm',

+ 5
- 0
releasenotes/notes/fs-drv-chunk-sz-a1b2f6a72fad92d5.yaml View File

@@ -0,0 +1,5 @@
1
+---
2
+fixes:
3
+  - |
4
+    The filesystem driver is now using a configurable chunk size. Increasing it
5
+    may avoid bottlenecks.

Loading…
Cancel
Save