Skip to content

Commit 4ad50a7

Browse files
committedJun 30, 2016
[Spatialite provider] Make sure to release dangling connections on provider closing
Fixes #15137
1 parent 2d825bc commit 4ad50a7

File tree

2 files changed

+86
-0
lines changed

2 files changed

+86
-0
lines changed
 

‎src/providers/spatialite/qgsspatialiteprovider.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -600,6 +600,7 @@ QgsSpatiaLiteProvider::QgsSpatiaLiteProvider( QString const &uri )
600600
QgsSpatiaLiteProvider::~QgsSpatiaLiteProvider()
601601
{
602602
closeDb();
603+
invalidateConnections( mSqlitePath );
603604
}
604605

605606
QgsAbstractFeatureSource* QgsSpatiaLiteProvider::featureSource() const

‎tests/src/python/test_provider_spatialite.py

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,21 @@
3737
TEST_DATA_DIR = unitTestDataPath()
3838

3939

40+
def count_opened_filedescriptors(filename_to_test):
41+
count = -1
42+
if sys.platform.startswith('linux'):
43+
count = 0
44+
open_files_dirname = '/proc/%d/fd' % os.getpid()
45+
filenames = os.listdir(open_files_dirname)
46+
for filename in filenames:
47+
full_filename = open_files_dirname + '/' + filename
48+
if os.path.exists(full_filename):
49+
link = os.readlink(full_filename)
50+
if os.path.basename(link) == os.path.basename(filename_to_test):
51+
count += 1
52+
return count
53+
54+
4055
class TestQgsSpatialiteProvider(unittest.TestCase, ProviderTestCase):
4156

4257
@classmethod
@@ -217,5 +232,75 @@ def test_invalid_iterator(self):
217232
layer = None
218233
os.unlink(corrupt_dbname)
219234

235+
# FIXME: this test case does not work whereas equivalent OGR one does
236+
# I believe the issue is that spatialite should have a Qgs
237+
def testNoDanglingFileDescriptorAfterCloseVariant1(self):
238+
''' Test that when closing the provider all file handles are released '''
239+
240+
temp_dbname = self.dbname + '.no_dangling_test1'
241+
shutil.copy(self.dbname, temp_dbname)
242+
243+
vl = QgsVectorLayer("dbname=%s table=test_n (geometry)" % temp_dbname, "test_n", "spatialite")
244+
self.assertTrue(vl.isValid())
245+
# The iterator will take one extra connection
246+
myiter = vl.getFeatures()
247+
print(vl.featureCount())
248+
# Consume one feature but the iterator is still opened
249+
f = next(myiter)
250+
self.assertTrue(f.isValid())
251+
252+
if sys.platform.startswith('linux'):
253+
self.assertEqual(count_opened_filedescriptors(temp_dbname), 2)
254+
255+
# does NO release one file descriptor, because shared with the iterator
256+
del vl
257+
258+
# Non portable, but Windows testing is done with trying to unlink
259+
if sys.platform.startswith('linux'):
260+
self.assertEqual(count_opened_filedescriptors(temp_dbname), 2)
261+
262+
f = next(myiter)
263+
self.assertTrue(f.isValid())
264+
265+
# Should release one file descriptor
266+
del myiter
267+
268+
# Non portable, but Windows testing is done with trying to unlink
269+
if sys.platform.startswith('linux'):
270+
self.assertEqual(count_opened_filedescriptors(temp_dbname), 0)
271+
272+
# Check that deletion works well (can only fail on Windows)
273+
os.unlink(temp_dbname)
274+
self.assertFalse(os.path.exists(temp_dbname))
275+
276+
def testNoDanglingFileDescriptorAfterCloseVariant2(self):
277+
''' Test that when closing the provider all file handles are released '''
278+
279+
temp_dbname = self.dbname + '.no_dangling_test2'
280+
shutil.copy(self.dbname, temp_dbname)
281+
282+
vl = QgsVectorLayer("dbname=%s table=test_n (geometry)" % temp_dbname, "test_n", "spatialite")
283+
self.assertTrue(vl.isValid())
284+
self.assertTrue(vl.isValid())
285+
# Consume all features.
286+
myiter = vl.getFeatures()
287+
for feature in myiter:
288+
pass
289+
# The iterator is closed
290+
if sys.platform.startswith('linux'):
291+
self.assertEqual(count_opened_filedescriptors(temp_dbname), 2)
292+
293+
# Should release one file descriptor
294+
del vl
295+
296+
# Non portable, but Windows testing is done with trying to unlink
297+
if sys.platform.startswith('linux'):
298+
self.assertEqual(count_opened_filedescriptors(temp_dbname), 0)
299+
300+
# Check that deletion works well (can only fail on Windows)
301+
os.unlink(temp_dbname)
302+
self.assertFalse(os.path.exists(temp_dbname))
303+
304+
220305
if __name__ == '__main__':
221306
unittest.main()

0 commit comments

Comments
 (0)
Please sign in to comment.