Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor sqlthread #1794

Draft
wants to merge 1 commit into
base: v0.6
Choose a base branch
from

Conversation

cis-muzahid
Copy link
Contributor

@cis-muzahid cis-muzahid commented Jul 28, 2021

Refactor sqlthread and add test cases for setting versions and SQL internal function called create_function

@PeterSurda PeterSurda marked this pull request as draft July 28, 2021 08:35
src/class_sqlThread.py Outdated Show resolved Hide resolved
Upgrade Db with respect to versions
"""

conn, cur = connection_build()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

here allow to call it optionally with a parameter for in memory database

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pass arguments with DB file name

self.conn = sqlite3.connect(state.appdata + 'messages.dat')
self.conn.text_factory = str
self.cur = self.conn.cursor()
self.conn, self.cur = connection_build()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this should be in parent class

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inherit connection vars from UpgradeDB class

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved in to __init__

self.conn.commit()

settingsversion = 4
settingsversion = self.earlier_setting_version(settingsversion)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this should be in parent class

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

@@ -465,10 +349,14 @@ def run(self): # pylint: disable=too-many-locals, too-many-branches, too-many-s
else:
logger.error(err)

# Let us check to see the last time we vaccumed the messages.dat file.
# If it has been more than a month let's do it now.
def check_vaccumed(self): # pylint: disable=too-many-locals, too-many-branches, too-many-statements,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

move to parent

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

vacuum not vaccum

@@ -635,8 +523,45 @@ def run(self): # pylint: disable=too-many-locals, too-many-branches, too-many-s
helper_sql.sqlReturnQueue.put((self.cur.fetchall(), rowcount))
# helper_sql.sqlSubmitQueue.task_done()

def earlier_setting_version(self, settingsversion):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

move to parent

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

different name, to show it's related to BMConfigParser version rather than sql version

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change name to upgrade_config_parser_setting_version


def run(self): # pylint: disable=too-many-locals, too-many-branches, too-many-statements
def run(self): # pylint: disable=too-many-locals, too-many-branches, too-many-statements,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

only this should be in this class, the other functionality should be refactored into methods and put into parent.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

self.cur.execute(item, parameters)


class sqlThread(threading.Thread, UpgradeDB):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe an UpgradeDB object would be an attribute of the sqlThread rarther than sqlThread 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.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changes done,
Refactored code and kept in Upgrade DB,

@cis-muzahid cis-muzahid changed the title Test refactor sqlthread Refactor sqlthread Jul 30, 2021
src/class_sqlThread.py Show resolved Hide resolved
def __init__(self):
self._current_level = None
self.max_level = 11
# self.conn, self.cur = connection_build('messages.dat')
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done


def __init__(self):
threading.Thread.__init__(self, name="SQL")
def connection_build(file_name):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Put this inside UpgradeDB

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done


def __get_current_settings_version(self):
"""
Upgrade Db with respect to their versions
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

update docstring

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done


def _upgrade_one_level_sql_statement(self, file_name):
"""
Execute SQL files and queries
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

update docstring

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done


helper_startup.updateConfig()
def embaded_version(self):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should be called something like init_database

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changes are done for that and, but for some query I applied same query script.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's call it upgrade_schema_if_old_version

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed def name to upgrade_schema_if_old_version

@@ -635,8 +523,45 @@ def run(self): # pylint: disable=too-many-locals, too-many-branches, too-many-s
helper_sql.sqlReturnQueue.put((self.cur.fetchall(), rowcount))
# helper_sql.sqlSubmitQueue.task_done()

def earlier_setting_version(self, settingsversion):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

different name, to show it's related to BMConfigParser version rather than sql version

# If the settings version is equal to 2 or 3 then the
# sqlThread will modify the pubkeys table and change
# the settings version to 4.
settingsversion = BMConfigParser().getint(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

write getter + setter for this

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Applied setter and getter

# call create_function for encode address
self.create_function(self.conn)

self.initiate_database(self.cur, self.conn)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Something like this to skip init when running tests:

if not self.instanceof(MockDB):
   self.initiate_database()

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

managed in earlier logic used in memory for test mocking

src/debug.py Outdated Show resolved Hide resolved
@g1itch
Copy link
Collaborator

g1itch commented Aug 9, 2021

Your sql directories are not python packages and should not contain the empty __init__ modules. If you want to install SQL scripts with the app, put them into the package data: https://github.com/Bitmessage/PyBitmessage/blob/v0.6/setup.py#L137
This doesn't apply to tests, they are not installed, and you may find the files based on os.path.abspath(__file__)

@@ -0,0 +1,10 @@
DROP TABLE objectprocessorqueue;

CREATE TABLE IF NOT EXISTS `knownnodes` (
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cool (; I haven't seen this used

$ sqlite3 .config/PyBitmessage/messages.dat
SQLite version 3.34.1 2021-01-20 14:10:07
Enter ".help" for usage hints.
sqlite> select * from knownnodes;
Error: no such table: knownnodes

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the table was deleted in a later version.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

@@ -0,0 +1,10 @@
DROP TABLE objectprocessorqueue;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why drop here, if you are going to create it later?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you're right, if it's removed and there is an error, it means there is a bug somewhere

`payload` blob DEFAULT NULL,
`integer` integer NOT NULL,
UNIQUE(hash) ON CONFLICT REPLACE
) ;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see a difference from the previous version - in the init_version_6.sql

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I looked through the tests and instructed to redesign how they perform setup.

@PeterSurda
Copy link
Member

@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.

@g1itch
Copy link
Collaborator

g1itch commented Aug 9, 2021

@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.

@g1itch
Copy link
Collaborator

g1itch commented Aug 9, 2021

By the way, the core test suite reports an interesting issue here: https://buildbot.bitmessage.org/#builders/25/builds/1515

self.max_level = 11
self.conn, self.cur = self.connection_build('messages.dat')

def connection_build(self, file_name=None):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

def connection_build(self, file_name='messages.dat'):

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

applied changes method name to __connection_build_internal and pass file_name

return self.__get_current_settings_version()

@sql_schema_version.setter
def sql_schema_version(self, current_level):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

instead of current_level use ignore

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removed current_level

item = '''update settings set value=? WHERE key='version';'''
parameters = (current_level + 1,)
self.cur.execute(item, parameters)
self._current_level = self.__get_current_settings_version()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

variable self.current_level shouldn't be needed

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now its

    def sql_schema_version(self):
        """
            Update version with one level
        """
        item = '''update settings set value=value+1 WHERE key='version';'''
        self.cur.execute(item)
        self._current_level = self.__get_current_settings_version()

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Its changed into

        self.cur.execute(item, self.__get_current_settings_version() + 1)

Because its not taking value+1

self.cur.execute(item, parameters)
self.conn.commit()

settingsversion = 3
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

separate getter setter for settingsversion

# Redefinition-of-parameters-type-from-tuple-to-str, R0204, line-too-long, E501
"""Process SQL queries from `.helper_sql.sqlSubmitQueue`"""
helper_sql.sql_available = True
self.conn, self.cur = UpgradeDB().conn, UpgradeDB().cur
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

insetad just create one object and save it, like

self.db = UpgradeDB()

and then just reference
self.db.cur.execute(blabla)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

passed while initialise

self.cur.execute('PRAGMA secure_delete = true')

# call create_function for encode address
self.create_function(self.conn)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

self.db.create_function(blabla)

# call create_function for encode address
self.create_function(self.conn)

self.initiate_database(self.cur, self.conn)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

self.db.initialize_schema()

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed into initialize_schema

# version we are on can stay embedded in the messages.dat file. Let us
# check to see if the settings table exists yet.

self.embaded_version()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

changed to upgrade_schema_if_old_version

@cis-muzahid cis-muzahid mentioned this pull request Nov 8, 2021
@PeterSurda PeterSurda mentioned this pull request Nov 16, 2021
@cis-muzahid cis-muzahid force-pushed the test_refactor_sqlthread branch 2 times, most recently from d5296dd to a55c086 Compare November 24, 2021 09:39
Copy link
Collaborator

@g1itch g1itch left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Barely readable ); The tests/sql seems duplicating sql

src/tests/sql/init_version_7.sql Outdated Show resolved Hide resolved
setup.py Outdated
@@ -137,7 +137,7 @@ def run(self):
package_data={'': [
'bitmessageqt/*.ui', 'bitmsghash/*.cl', 'sslkeys/*.pem',
'translations/*.ts', 'translations/*.qm',
'images/*.png', 'images/*.ico', 'images/*.icns'
'images/*.png', 'images/*.ico', 'images/*.icns', 'sql/*.py', 'sql/*.sql'
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand the purpose of this empty sql/__init__.py and especially listing it in the package_data.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The file was removed, but the reference in setup.py still persists. @cis-muzahid please delete this reference, and also delete the file src/tests/sql/__init__.py, that is also unnecessary.

@@ -8,6 +8,7 @@
import sys
import threading
import time
import logging
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isort

class BitmessageDB(object):
"""
Upgrade Db with respect to versions
"""
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

strange formatting

"""
Get current setting Version
"""
item = '''SELECT value FROM settings WHERE key='version';'''
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need for semicolon

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There was a problem, we found out what it is, will be fixed in next commit.

@property
def sql_config_settings_version(self):
"""
Getter for BmConfigparser
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BMConfigParser (obj)

"MainWindow",
'Alert: Your disk or data storage volume is full. Bitmessage will now exit.'),
True)))
os._exit(0)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Weird formatting

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree

' Here is the actual error message thrown by the sqlThread: %s',
str(item),
str(repr(parameters)),
str(err))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These casts seem redundant

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tend to agree. Something like traceback.format_exc would be better.

queryreturn = sqlExecute("INSERT INTO testtbl VALUES(101);")
self.assertEqual(queryreturn, 1)

queryreturn = sqlQuery(''' SELECT * FROM testtbl ''')
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"SELECT * FROM testtbl"

@@ -409,6 +409,22 @@ def test_adding_two_same_case_sensitive_addresses(self):
self.delete_address_from_addressbook(address1)
self.delete_address_from_addressbook(address2)

def test_sqlscripts(self):
""" Testing sql statements"""
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What it tests?

Copy link
Collaborator

@g1itch g1itch left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see no point in another review since my previous comments are mostly ignored.

parameters = helper_sql.sqlSubmitQueue.get()
rowcount = 0
try:
self.db.cur.execute(item, parameters)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

item is a bad name. Use query.

Copy link
Member

@PeterSurda PeterSurda left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are still a couple of unresolved conversations.

setup.py Outdated
@@ -137,7 +137,7 @@ def run(self):
package_data={'': [
'bitmessageqt/*.ui', 'bitmsghash/*.cl', 'sslkeys/*.pem',
'translations/*.ts', 'translations/*.qm',
'images/*.png', 'images/*.ico', 'images/*.icns'
'images/*.png', 'images/*.ico', 'images/*.icns', 'sql/*.py', 'sql/*.sql'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The file was removed, but the reference in setup.py still persists. @cis-muzahid please delete this reference, and also delete the file src/tests/sql/__init__.py, that is also unnecessary.

"MainWindow",
'Alert: Your disk or data storage volume is full. Bitmessage will now exit.'),
True)))
os._exit(0)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree

@cis-muzahid cis-muzahid force-pushed the test_refactor_sqlthread branch 3 times, most recently from 2b89a05 to d6acbc3 Compare February 23, 2022 10:39
@cis-muzahid cis-muzahid force-pushed the test_refactor_sqlthread branch 2 times, most recently from c953c10 to de89853 Compare March 16, 2022 09:27
Copy link
Member

@PeterSurda PeterSurda left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PR shouldn't remove the *.sql files. It should ignore them.

Copy link
Member

@PeterSurda PeterSurda left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unstage the sql files

@kdcis kdcis force-pushed the test_refactor_sqlthread branch 2 times, most recently from 676025a to f61b1c1 Compare March 25, 2022 17:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants