Refactor sqlthread #1794
No reviewers
Labels
No Label
bug
build
dependencies
developers
documentation
duplicate
enhancement
formatting
invalid
legal
mobile
obsolete
packaging
performance
protocol
question
refactoring
regression
security
test
translation
usability
wontfix
No Milestone
No project
No Assignees
1 Participants
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: Bitmessage/PyBitmessage-2024-12-04#1794
Loading…
Reference in New Issue
Block a user
No description provided.
Delete Branch "cis-muzahid/test_refactor_sqlthread"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Refactor sqlthread and add test cases for setting versions and SQL internal function called create_function
@ -17,128 +17,100 @@ try:
import state
this should contain an argument that allows to use an in memory database instead of the file.
@ -17,128 +17,100 @@ try:
import state
here allow to call it optionally with a parameter for in memory database
@ -17,128 +17,100 @@ try:
import state
this should be in parent class
@ -491,3 +210,3 @@
parameters = (int(time.time()),)
self.cur.execute(item, parameters)
self.cur.execute(query, parameters)
this should be in parent class
@ -641,0 +430,4 @@
helper_sql.sql_available = True
config_ready.wait()
this should all be in parent class
@ -641,0 +345,4 @@
'(while movemessagstoappdata) Alert: Your disk or data storage volume is full.'
' sqlThread will now exit.')
queues.UISignalQueue.put((
'alert', (
move to parent
move to parent
@ -17,128 +17,100 @@ try:
import state
only this should be in this class, the other functionality should be refactored into methods and put into parent.
@ -17,128 +17,100 @@ try:
import state
maybe an
UpgradeDB
object would be an attribute of thesqlThread
rarther thansqlThread
inheriting it. That way we isolate the DB stuff and can test it without threading, and the thread would need to use the same interfaces as the test.@ -17,128 +17,100 @@ try:
import state
Done
@ -17,128 +17,100 @@ try:
import state
pass arguments with DB file name
@ -17,128 +17,100 @@ try:
import state
Inherit connection vars from UpgradeDB class
@ -17,128 +17,100 @@ try:
import state
Changes done,
Refactored code and kept in Upgrade DB,
@ -17,128 +17,100 @@ try:
import state
done
Done
@ -641,0 +345,4 @@
'(while movemessagstoappdata) Alert: Your disk or data storage volume is full.'
' sqlThread will now exit.')
queues.UISignalQueue.put((
'alert', (
Done
@ -641,0 +430,4 @@
helper_sql.sql_available = True
config_ready.wait()
Done
@ -491,3 +210,3 @@
parameters = (int(time.time()),)
self.cur.execute(item, parameters)
self.cur.execute(query, parameters)
Done
make another class which overrides this to point to in-memory database, this can then be used for tests. You can call it something like
class MockDB(UpgradeDB)
Put this inside
UpgradeDB
update docstring
update docstring
this should return the version, not store
should not store
use atomic increment
But check for types (string vs. int).
no need for this
typo
should be called something like
init_database
@ -86,2 +80,2 @@
if str(err) == 'table inbox already exists':
logger.debug('Database file already exists.')
logger.debug(
'ERROR trying to initialize database. Error message: %s\n', str(err))
@getter something
@ -423,0 +132,4 @@
# too-many-branches, too-many-statements
"""
Check if sqlite can store binary zeros.
"""
we should at least differenciate between SQL exceptions and other exceptions (e.g. file not found)
this check is only for testing if the database already has been initialised. It wasn't used to check upgrade levels.
@ -641,0 +397,4 @@
_translate(
"MainWindow",
"Disk full"),
_translate(
write getter + setter for this
Something like this to skip init when running tests:
different name, to show it's related to
BMConfigParser
version rather than sql versionputh these lines together
Change name to
upgrade_config_parser_setting_version
@ -17,128 +17,100 @@ try:
import state
Moved in to
__init__
@ -86,2 +80,2 @@
if str(err) == 'table inbox already exists':
logger.debug('Database file already exists.')
logger.debug(
'ERROR trying to initialize database. Error message: %s\n', str(err))
Already using getter for the same
Done
@ -423,0 +132,4 @@
# too-many-branches, too-many-statements
"""
Check if sqlite can store binary zeros.
"""
Differed between
except IOError as err:
andexcept Exception as err:
Not add others exceptions
Removed this line
return value
You don't need this at all. Just don't use debug in
sqlThread
and make it like other threads to use own logger, gotten in the class definition, look: https://github.com/Bitmessage/PyBitmessage/blob/v0.6/src/network/threads.py#L9I reverted it once already:
b75585f2
Why don't you add the exception type?
Your
sql
directories are not python packages and should not contain the empty__init__
modules. If you want to installSQL
scripts with the app, put them into the package data: https://github.com/Bitmessage/PyBitmessage/blob/v0.6/setup.py#L137This doesn't apply to tests, they are not installed, and you may find the files based on
os.path.abspath(__file__)
Cool (; I haven't seen this used
Why drop here, if you are going to create it later?
I don't see a difference from the previous version - in the
init_version_6.sql
This PR is still a WIP, you don't need to look at it yet, except in some cases like these imports which are not my strength.
I haven't reviewed the SQL files yet, I'm focusing on getting the structure of classes and tests right, it's already at like 3rd iteration.
I receive a notification from this PR, because it was not originally a draft, it was me, who made it draft.
@g1itch This PR should among other things separate the SQL execution from threads, so that you can run the tests without launching the SQL thread. There is a lot of work and that's why it's taking long.
I see. I have no problem with the speed yet. I'm glad to see many line of code deleted in this PR. But I'd prefer to report the strange things, I can see in the code before it got merged. Because I believe we can broke it harder than before. More tests will help to avoid such case.
By the way, the core test suite reports an interesting issue here: https://buildbot.bitmessage.org/#builders/25/builds/1515
Done
Done
Done
@ -641,0 +397,4 @@
_translate(
"MainWindow",
"Disk full"),
_translate(
managed in earlier logic used in memory for test mocking
Done
returned that value
convert into this str(int(current_level) + 1)
Changes are done for that and, but for some query I applied same query script.
Applied
Removed that
@ -24,4 +23,3 @@
from .addresses import encodeAddress
from .bmconfigparser import config, config_ready
from .debug import logger
from .tr import _translate
@ -24,4 +23,3 @@
from .addresses import encodeAddress
from .bmconfigparser import config, config_ready
from .debug import logger
from .tr import _translate
instead of
current_level
useignore
@ -24,4 +23,3 @@
from .addresses import encodeAddress
from .bmconfigparser import config, config_ready
from .debug import logger
from .tr import _translate
variable
self.current_level
shouldn't be needed@ -641,0 +398,4 @@
"MainWindow",
"Disk full"),
_translate(
"MainWindow",
separate getter setter for settingsversion
@ -641,0 +398,4 @@
"MainWindow",
"Disk full"),
_translate(
"MainWindow",
insetad just create one object and save it, like
and then just reference
self.db.cur.execute(blabla)
@ -641,0 +398,4 @@
"MainWindow",
"Disk full"),
_translate(
"MainWindow",
self.db.create_function(blabla)
@ -641,0 +398,4 @@
"MainWindow",
"Disk full"),
_translate(
"MainWindow",
self.db.initialize_schema()
@ -641,0 +398,4 @@
"MainWindow",
"Disk full"),
_translate(
"MainWindow",
typo
@ -24,4 +23,3 @@
from .addresses import encodeAddress
from .bmconfigparser import config, config_ready
from .debug import logger
from .tr import _translate
just
self._connection_build('messages.dat')
@ -24,4 +23,3 @@
from .addresses import encodeAddress
from .bmconfigparser import config, config_ready
from .debug import logger
from .tr import _translate
instead of return, just
and then in
MockDB
just override__init__
to call `self._connection_build(':memory:')Then you can remove all ifs here
change into
'''update settings set value=value+1 WHERE key='version';'''
@ -641,0 +397,4 @@
_translate(
"MainWindow",
"Disk full"),
_translate(
Applied setter and getter
@ -24,4 +23,3 @@
from .addresses import encodeAddress
from .bmconfigparser import config, config_ready
from .debug import logger
from .tr import _translate
removed current_level
@ -24,4 +23,3 @@
from .addresses import encodeAddress
from .bmconfigparser import config, config_ready
from .debug import logger
from .tr import _translate
Now its
@ -641,0 +398,4 @@
"MainWindow",
"Disk full"),
_translate(
"MainWindow",
passed while initialise
@ -24,4 +23,3 @@
from .addresses import encodeAddress
from .bmconfigparser import config, config_ready
from .debug import logger
from .tr import _translate
Done
get rid of
self._current_level
let's call it
upgrade_schema_if_old_version
@ -24,4 +23,3 @@
from .addresses import encodeAddress
from .bmconfigparser import config, config_ready
from .debug import logger
from .tr import _translate
make it a class variable
no static method
no return, just directly assign the
self.con
andself.cur
herealso declare
rename to
this should be internal to the object
get rid of
self._current_level
no need for caching, this is uses only during startup and tests, and only a dozen times, no need to optimize, just use the property
@ -49,1 +69,4 @@
self.initialise_sql("init_version_{}".format(file_name))
def initialise_sql(self, file_name):
try:
add a new method
write a meanignful docstring
@ -641,0 +397,4 @@
_translate(
"MainWindow",
"Disk full"),
_translate(
at the bottom add a new class
@ -24,4 +23,3 @@
from .addresses import encodeAddress
from .bmconfigparser import config, config_ready
from .debug import logger
from .tr import _translate
applied changes method name to
__connection_build_internal
and pass file_name@ -24,4 +23,3 @@
from .addresses import encodeAddress
from .bmconfigparser import config, config_ready
from .debug import logger
from .tr import _translate
Its changed into
Because its not taking
value+1
@ -641,0 +398,4 @@
"MainWindow",
"Disk full"),
_translate(
"MainWindow",
Changed into
initialize_schema
@ -24,4 +23,3 @@
from .addresses import encodeAddress
from .bmconfigparser import config, config_ready
from .debug import logger
from .tr import _translate
Changed
@ -24,4 +23,3 @@
from .addresses import encodeAddress
from .bmconfigparser import config, config_ready
from .debug import logger
from .tr import _translate
@ -24,4 +23,3 @@
from .addresses import encodeAddress
from .bmconfigparser import config, config_ready
from .debug import logger
from .tr import _translate
Done
@ -24,4 +23,3 @@
from .addresses import encodeAddress
from .bmconfigparser import config, config_ready
from .debug import logger
from .tr import _translate
Done
@ -24,4 +23,3 @@
from .addresses import encodeAddress
from .bmconfigparser import config, config_ready
from .debug import logger
from .tr import _translate
Removed static method
@ -24,4 +23,3 @@
from .addresses import encodeAddress
from .bmconfigparser import config, config_ready
from .debug import logger
from .tr import _translate
Done
@ -24,4 +23,3 @@
from .addresses import encodeAddress
from .bmconfigparser import config, config_ready
from .debug import logger
from .tr import _translate
Done
@ -24,4 +23,3 @@
from .addresses import encodeAddress
from .bmconfigparser import config, config_ready
from .debug import logger
from .tr import _translate
Done
@ -641,0 +398,4 @@
"MainWindow",
"Disk full"),
_translate(
"MainWindow",
changed to
upgrade_schema_if_old_version
Done
its changed into
Changed def name to
upgrade_schema_if_old_version
@ -24,4 +23,3 @@
from .addresses import encodeAddress
from .bmconfigparser import config, config_ready
from .debug import logger
from .tr import _translate
use getter
and create an empty sql script for level 1 (one that doesn't change anything), like
SELECT NULL
@ -49,1 +69,4 @@
self.initialise_sql("init_version_{}".format(file_name))
def initialise_sql(self, file_name):
try:
@ -641,0 +407,4 @@
'Major error occurred when trying to execute a SQL statement within the sqlThread.'
' Please tell Atheros about this error message or post it in the forum!'
' Error occurred while trying to execute statement: "%s" Here are the parameters;'
' you might want to censor this data with asterisks (***)'
make this into a separate method
no
@ -2,43 +2,214 @@
# flake8: noqa:E402
import os
import tempfile
should be called something like
TestUpgradeDB
maybe here in the decorator create the
self.db
objectreceivedtime
andpayload
are swappedreceivedtime
andpayload
are swapped@ -2,43 +2,214 @@
# flake8: noqa:E402
import os
import tempfile
Done
@ -2,43 +2,214 @@
# flake8: noqa:E402
import os
import tempfile
Done
@ -49,1 +69,4 @@
self.initialise_sql("init_version_{}".format(file_name))
def initialise_sql(self, file_name):
try:
Done
@ -641,0 +407,4 @@
'Major error occurred when trying to execute a SQL statement within the sqlThread.'
' Please tell Atheros about this error message or post it in the forum!'
' Error occurred while trying to execute statement: "%s" Here are the parameters;'
' you might want to censor this data with asterisks (***)'
Changed approach
@ -641,0 +407,4 @@
'Major error occurred when trying to execute a SQL statement within the sqlThread.'
' Please tell Atheros about this error message or post it in the forum!'
' Error occurred while trying to execute statement: "%s" Here are the parameters;'
' you might want to censor this data with asterisks (***)'
Done
@ -24,4 +23,3 @@
from .addresses import encodeAddress
from .bmconfigparser import config, config_ready
from .debug import logger
from .tr import _translate
os.path.join
not
upgrade
,initialize
also
initialize
instead ofupgrade
don't exit, log an error message
@ -93,0 +84,4 @@
def sql_schema_version(self):
"""
Getter for get current schema version
"""
this should remain here
@ -96,3 +90,1 @@
# the settings version to 4.
settingsversion = config.getint(
'bitmessagesettings', 'settingsversion')
@sql_schema_version.setter
To make life easier, this should remain.
columns
@ -641,0 +401,4 @@
"MainWindow",
'Alert: Your disk or data storage volume is full. Bitmessage will now exit.'),
True)))
os._exit(0)
you can put it together with the vaccum time update
@ -641,0 +407,4 @@
'Major error occurred when trying to execute a SQL statement within the sqlThread.'
' Please tell Atheros about this error message or post it in the forum!'
' Error occurred while trying to execute statement: "%s" Here are the parameters;'
' you might want to censor this data with asterisks (***)'
CAST(strftime('%s', 'now') AS STR)
@ -2,43 +2,214 @@
# flake8: noqa:E402
import os
import tempfile
remove this
remove this
remove this method
delete his method
delete this method
There are still "DEFAULT" and "NOT NULL" declarations in some places where they are missing in the old ones.
this file isn't used
if table inbox not already exists, then initialize_schema
Fixes #1710
The comments in the
sql/init_version_*.sql
are not helpful. They just repeat the statements in different words. Instead, the original comments should be kept.@ -2,43 +2,214 @@
# flake8: noqa:E402
import os
import tempfile
why do you need this? how about just using
cls.test_db.conn
andcls.test_db.cur
?check_vacuumed
should end at line 229. Line 231 should be moved to parent method, and thewhile
loop that follows should have its own function and also be called from parent.@ -641,0 +345,4 @@
'(while movemessagstoappdata) Alert: Your disk or data storage volume is full.'
' sqlThread will now exit.')
queues.UISignalQueue.put((
'alert', (
vacuum
notvaccum
sql/*.py
,sql/*.sql
so that it doesn't pick up things like__init__.pyc
I think the table was deleted in a later version.
@ -594,0 +229,4 @@
logger.info('Created messages database file')
except Exception as err:
if str(err) == 'table inbox already exists':
logger.debug('Database file already exists.')
something like this
SQL statements mostly ok, couple of minor changes requested.
time
is a reserved word, should useinstead, just in case.
here too
duplicate of
upg_sc_if_old_ver_2
, delete file.remove
DEFAULT
, should be the same as original, in the whole file.also below once again
Here
sqlExecute
so that we test it too.use
sqlExecute
here and check it's return value (number of modified rows, i.e. should be1
here)This has been fixed now, as most of the other things you pointed out. It should be ready for you to review in a couple of days, I'll let you know.
@ -2,43 +2,214 @@
# flake8: noqa:E402
import os
import tempfile
67-70 not needed anymore
remove file
@ -45,0 +84,4 @@
and Upgrade DB schema for all versions
"""
def wrapper(*args):
"""
@ -2,43 +2,214 @@
# flake8: noqa:E402
import os
import tempfile
just remove this section, no comment
@ -2,43 +2,214 @@
# flake8: noqa:E402
import os
import tempfile
duplicate line
@ -2,43 +2,214 @@
# flake8: noqa:E402
import os
import tempfile
this is not helpful
Please make the changes.
@ -2,43 +2,214 @@
# flake8: noqa:E402
import os
import tempfile
setUp
shouldn't be a class methodRemove obsolete comments.
@ -423,0 +131,4 @@
def check_columns_can_store_binary_null(self): # pylint: disable=too-many-locals,
# too-many-branches, too-many-statements
"""
Check if sqlite can store binary zeros.
why line 149 and 150? Makes no sense to put it here.
Barely readable ); The
tests/sql
seems duplicatingsql
I don't understand the purpose of this empty
sql/__init__.py
and especially listing it in the package_data.@ -4,3 +4,4 @@
import logging
import os
import shutil # used for moving the messages.dat file
isort
@ -17,128 +17,100 @@ try:
import state
strange formatting
No need for semicolon
Why are you introducing more pylint warnings here?
I think
logger.debug('Error while trying to initialize...', exc_info=True)
is enough here. No need forsys.stderr.write()
and err.It doesn't look like the method docstring
@ -576,0 +220,4 @@
def initialize_schema(self):
"""
Initialise Db schema
"""
I don't understand this
os._exit(0)
. Why don't you usesys.exit('Error while trying to create database file..')
? What is it mean "in1111"?BMConfigParser
(obj)Weird formatting
These casts seem redundant
"SELECT * FROM testtbl"
What it tests?
strange expression
I see no point in another review since my previous comments are mostly ignored.
There are two exception hanlders, one for IOError (disk failure, disk full), and everything else. We may want to handle these situations differently, and we don't know what all kinds of exceptions can be thrown, so I recommended doing it this way.
@ -17,128 +17,100 @@ try:
import state
There was a problem, we found out what it is, will be fixed in next commit.
@ -488,3 +207,3 @@
True)))
os._exit(0)
item = '''update settings set value=? WHERE key='lastvacuumtime';'''
query = "update settings set value=? WHERE key='lastvacuumtime'"
item
is a bad name. Usequery
.I tend to agree. Something like
traceback.format_exc
would be better.you're right, if it's removed and there is an error, it means there is a bug somewhere
It looks like some weird leftover of deleted code. Since the current upgrade code deletes it, we should keep it, otherwise we'd have to test against ancient versions.
I looked through the tests and instructed to redesign how they perform setup.
There are still a couple of unresolved conversations.
The file was removed, but the reference in
setup.py
still persists. @cis-muzahid please delete this reference, and also delete the filesrc/tests/sql/__init__.py
, that is also unnecessary.I agree
The PR shouldn't remove the
*.sql
files. It should ignore them.unstage the sql files