mirror of
https://github.com/correl/dejavu.git
synced 2024-11-23 19:19:53 +00:00
Added a foreign key relationship to the create table statements.
- MySQL will also use the InnoDB engine now. - Added a ping call in the MySQL Cursor cache mechanism - Added a rollback call when a MySQLError occurs - Removed 'delete_orphans' which is not needed anymore due to foreign key constraints and delete on cascade - Changed SQLDatabase to accept options to create a cursor factory, instead of taking a pre-created cursor factory
This commit is contained in:
parent
bed11f3de7
commit
6f4cadafbb
2 changed files with 36 additions and 27 deletions
|
@ -33,15 +33,22 @@ class Cursor(object):
|
||||||
conn = self._cache.get_nowait()
|
conn = self._cache.get_nowait()
|
||||||
except Queue.Empty:
|
except Queue.Empty:
|
||||||
conn = mysql.connect(**options)
|
conn = mysql.connect(**options)
|
||||||
|
else:
|
||||||
|
# Ping the connection before using it from the cache.
|
||||||
|
conn.ping(True)
|
||||||
|
|
||||||
self.conn = conn
|
self.conn = conn
|
||||||
self.cursor_type = cursor_type
|
self.cursor_type = cursor_type
|
||||||
|
|
||||||
def __enter__(slf):
|
def __enter__(self):
|
||||||
self.cursor = self.conn.cursor(self.cursor_type)
|
self.cursor = self.conn.cursor(self.cursor_type)
|
||||||
return self.cursor
|
return self.cursor
|
||||||
|
|
||||||
def __exit__(self, type, value, traceback):
|
def __exit__(self, extype, exvalue, traceback):
|
||||||
|
# if we had a MySQL related error we try to rollback the cursor.
|
||||||
|
if extype is mysql.MySQLError:
|
||||||
|
self.cursor.rollback()
|
||||||
|
|
||||||
self.cursor.close()
|
self.cursor.close()
|
||||||
self.conn.commit()
|
self.conn.commit()
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
from __future__ import absolute_import
|
from __future__ import absolute_import
|
||||||
from binascii import unhexlify
|
from itertools import izip_longest
|
||||||
|
|
||||||
|
from dejavu.cursor import cursor_factory
|
||||||
from MySQLdb.cursors import Cursor
|
from MySQLdb.cursors import Cursor
|
||||||
|
|
||||||
|
|
||||||
class Database(object):
|
class Database(object):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super(Database, self).__init__()
|
super(Database, self).__init__()
|
||||||
|
@ -69,11 +71,13 @@ class SQLDatabase(Database):
|
||||||
`%s` mediumint unsigned not null,
|
`%s` mediumint unsigned not null,
|
||||||
`%s` int unsigned not null,
|
`%s` int unsigned not null,
|
||||||
INDEX(%s),
|
INDEX(%s),
|
||||||
UNIQUE(%s, %s, %s)
|
UNIQUE(%s, %s, %s),
|
||||||
);""" % (
|
FOREIGN KEY (%s) REFERENCES %s(%s) ON DELETE CASCADE
|
||||||
|
) ENGINE=INNODB;""" % (
|
||||||
FINGERPRINTS_TABLENAME, FIELD_HASH,
|
FINGERPRINTS_TABLENAME, FIELD_HASH,
|
||||||
FIELD_SONG_ID, FIELD_OFFSET, FIELD_HASH,
|
FIELD_SONG_ID, FIELD_OFFSET, FIELD_HASH,
|
||||||
FIELD_SONG_ID, FIELD_OFFSET, FIELD_HASH,
|
FIELD_SONG_ID, FIELD_OFFSET, FIELD_HASH,
|
||||||
|
FIELD_SONG_ID, SONGS_TABLENAME, FIELD_SONG_ID
|
||||||
)
|
)
|
||||||
|
|
||||||
CREATE_SONGS_TABLE = """
|
CREATE_SONGS_TABLE = """
|
||||||
|
@ -83,7 +87,7 @@ class SQLDatabase(Database):
|
||||||
`%s` tinyint default 0,
|
`%s` tinyint default 0,
|
||||||
PRIMARY KEY (`%s`),
|
PRIMARY KEY (`%s`),
|
||||||
UNIQUE KEY `%s` (`%s`)
|
UNIQUE KEY `%s` (`%s`)
|
||||||
);""" % (
|
) ENGINE=INNODB;""" % (
|
||||||
SONGS_TABLENAME, FIELD_SONG_ID, FIELD_SONGNAME, FIELD_FINGERPRINTED,
|
SONGS_TABLENAME, FIELD_SONG_ID, FIELD_SONGNAME, FIELD_FINGERPRINTED,
|
||||||
FIELD_SONG_ID, FIELD_SONG_ID, FIELD_SONG_ID,
|
FIELD_SONG_ID, FIELD_SONG_ID, FIELD_SONG_ID,
|
||||||
)
|
)
|
||||||
|
@ -141,18 +145,17 @@ class SQLDatabase(Database):
|
||||||
DELETE FROM %s WHERE %s = 0;
|
DELETE FROM %s WHERE %s = 0;
|
||||||
""" % (SONGS_TABLENAME, FIELD_FINGERPRINTED)
|
""" % (SONGS_TABLENAME, FIELD_FINGERPRINTED)
|
||||||
|
|
||||||
DELETE_ORPHANS = """
|
def __init__(self, **options):
|
||||||
delete from fingerprints
|
|
||||||
where not exists (
|
|
||||||
select * from songs where fingerprints.song_id = songs.song_id
|
|
||||||
);
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, cursor):
|
|
||||||
super(SQLDatabase, self).__init__()
|
super(SQLDatabase, self).__init__()
|
||||||
self.cursor = cursor
|
self.cursor = cursor_factory(**options)
|
||||||
|
|
||||||
def setup(self):
|
def setup(self):
|
||||||
|
"""
|
||||||
|
Creates any non-existing tables required for dejavu to function.
|
||||||
|
|
||||||
|
This also removes all songs that have been added but have no
|
||||||
|
fingerprints associated with them.
|
||||||
|
"""
|
||||||
with self.cursor() as cur:
|
with self.cursor() as cur:
|
||||||
cur.execute(self.CREATE_FINGERPRINTS_TABLE)
|
cur.execute(self.CREATE_FINGERPRINTS_TABLE)
|
||||||
cur.execute(self.CREATE_SONGS_TABLE)
|
cur.execute(self.CREATE_SONGS_TABLE)
|
||||||
|
@ -160,7 +163,11 @@ class SQLDatabase(Database):
|
||||||
|
|
||||||
def empty(self):
|
def empty(self):
|
||||||
"""
|
"""
|
||||||
Drops all tables and re-adds them. Be carfeul with this!
|
Drops tables created by dejavu and then creates them again
|
||||||
|
by calling `SQLDatabase.setup`.
|
||||||
|
|
||||||
|
.. warning:
|
||||||
|
This will result in a loss of data
|
||||||
"""
|
"""
|
||||||
with self.cursor() as cur:
|
with self.cursor() as cur:
|
||||||
cur.execute(self.DROP_FINGERPRINTS)
|
cur.execute(self.DROP_FINGERPRINTS)
|
||||||
|
@ -168,16 +175,11 @@ class SQLDatabase(Database):
|
||||||
|
|
||||||
self.setup()
|
self.setup()
|
||||||
|
|
||||||
def delete_orphans(self):
|
|
||||||
# TODO: SQLDatabase.DELETE_ORPHANS is not
|
|
||||||
# performant enough, need better query to
|
|
||||||
# delete fingerprints for which no song is tied to.
|
|
||||||
|
|
||||||
# with self.cursor() as cur:
|
|
||||||
# cur.execute(self.DELETE_ORPHANS)
|
|
||||||
pass
|
|
||||||
|
|
||||||
def delete_unfingerprinted_songs(self):
|
def delete_unfingerprinted_songs(self):
|
||||||
|
"""
|
||||||
|
Removes all songs that have no fingerprints associated with them.
|
||||||
|
"""
|
||||||
with self.cursor() as cur:
|
with self.cursor() as cur:
|
||||||
cur.execute(self.DELETE_UNFINGERPRINTED)
|
cur.execute(self.DELETE_UNFINGERPRINTED)
|
||||||
|
|
||||||
|
@ -188,8 +190,9 @@ class SQLDatabase(Database):
|
||||||
with self.cursor() as cur:
|
with self.cursor() as cur:
|
||||||
cur.execute(self.SELECT_UNIQUE_SONG_IDS)
|
cur.execute(self.SELECT_UNIQUE_SONG_IDS)
|
||||||
|
|
||||||
for row in cur:
|
for count, in cur:
|
||||||
return row['n']
|
return count
|
||||||
|
return 0
|
||||||
|
|
||||||
def get_num_fingerprints(self):
|
def get_num_fingerprints(self):
|
||||||
"""
|
"""
|
||||||
|
@ -304,7 +307,6 @@ class SQLDatabase(Database):
|
||||||
yield (sid, offset - mapper[hash])
|
yield (sid, offset - mapper[hash])
|
||||||
|
|
||||||
|
|
||||||
from itertools import izip_longest
|
|
||||||
def grouper(iterable, n, fillvalue=None):
|
def grouper(iterable, n, fillvalue=None):
|
||||||
args = [iter(iterable)] * n
|
args = [iter(iterable)] * n
|
||||||
return izip_longest(fillvalue=fillvalue, *args)
|
return izip_longest(fillvalue=fillvalue, *args)
|
||||||
|
|
Loading…
Reference in a new issue