SQLite playlist store: Greatly improved performance of playlist sync operations

CQTexperiment
Christopher Snowhill 2022-01-14 22:42:57 -08:00
parent 33f3b4f5a0
commit 74cd0f7da9
5 changed files with 52 additions and 63 deletions

View File

@ -12,6 +12,7 @@
NSInteger index; NSInteger index;
NSInteger shuffleIndex; NSInteger shuffleIndex;
NSInteger dbIndex; NSInteger dbIndex;
NSInteger entryId;
BOOL current; BOOL current;
BOOL removed; BOOL removed;
@ -86,6 +87,7 @@
@property NSInteger index; @property NSInteger index;
@property NSInteger shuffleIndex; @property NSInteger shuffleIndex;
@property NSInteger dbIndex; @property NSInteger dbIndex;
@property NSInteger entryId;
@property(readonly) NSString *status; @property(readonly) NSString *status;
@property(readonly) NSString *statusMessage; @property(readonly) NSString *statusMessage;

View File

@ -14,6 +14,7 @@
@synthesize index; @synthesize index;
@synthesize shuffleIndex; @synthesize shuffleIndex;
@synthesize dbIndex; @synthesize dbIndex;
@synthesize entryId;
@synthesize current; @synthesize current;
@synthesize removed; @synthesize removed;

View File

@ -747,7 +747,7 @@ static inline void dispatch_sync_reentrant(dispatch_queue_t queue, dispatch_bloc
for (i = 0; i < count; ++i) for (i = 0; i < count; ++i)
{ {
PlaylistEntry *pe = [store playlistGetItem:i]; PlaylistEntry *pe = [store playlistGetCachedItem:i];
pe.queuePosition = -1; pe.queuePosition = -1;

View File

@ -15,6 +15,7 @@
@private NSString *g_databasePath; @private NSString *g_databasePath;
@private sqlite3 *g_database; @private sqlite3 *g_database;
@private sqlite3_stmt *stmt[38]; @private sqlite3_stmt *stmt[38];
@private NSMutableArray *databaseMirror;
} }
@property (nonatomic, readwrite) NSString *databasePath; @property (nonatomic, readwrite) NSString *databasePath;
@ -32,6 +33,7 @@
- (void)playlistRemoveTracks:(int64_t)index forCount:(int64_t)count progressCall:(void(^)(double progress))callback; - (void)playlistRemoveTracks:(int64_t)index forCount:(int64_t)count progressCall:(void(^)(double progress))callback;
- (void)playlistRemoveTracksAtIndexes:(NSIndexSet *)indexes progressCall:(void(^)(double progress))callback; - (void)playlistRemoveTracksAtIndexes:(NSIndexSet *)indexes progressCall:(void(^)(double progress))callback;
- (PlaylistEntry *)playlistGetItem:(int64_t)index; - (PlaylistEntry *)playlistGetItem:(int64_t)index;
- (PlaylistEntry *)playlistGetCachedItem:(int64_t)index;
- (int64_t)playlistGetCount; - (int64_t)playlistGetCount;
#if 0 #if 0
- (void)playlistMoveObjectsInArrangedObjectsFromIndexes:(NSIndexSet *)indexSet toIndex:(NSUInteger)insertIndex; - (void)playlistMoveObjectsInArrangedObjectsFromIndexes:(NSIndexSet *)indexSet toIndex:(NSUInteger)insertIndex;

View File

@ -378,7 +378,7 @@ enum
select_playlist_out_track_id, select_playlist_out_track_id,
}; };
const char * query_select_playlist = "SELECT entryid, trackid FROM playlist WHERE (entryindex = ?) LIMIT 1"; const char * query_select_playlist = "SELECT entryid, trackid FROM playlist WHERE (entryindex = ?)";
enum enum
{ {
@ -635,6 +635,16 @@ static SQLiteStore *g_sharedStore = NULL;
} }
#undef PREPARE #undef PREPARE
size_t count = [self playlistGetCount];
databaseMirror = [[NSMutableArray alloc] init];
for (size_t i = 0; i < count; ++i)
{
PlaylistEntry *pe = [self playlistGetItem:i];
[databaseMirror addObject:pe];
}
return self; return self;
} }
} }
@ -1527,6 +1537,8 @@ static SQLiteStore *g_sharedStore = NULL;
return; return;
} }
[databaseMirror insertObjects:tracks atIndexes:indexes];
__block int64_t total_count = 0; __block int64_t total_count = 0;
[indexes enumerateRangesUsingBlock:^(NSRange range, BOOL * _Nonnull stop) { [indexes enumerateRangesUsingBlock:^(NSRange range, BOOL * _Nonnull stop) {
total_count += range.length; total_count += range.length;
@ -1639,6 +1651,8 @@ static SQLiteStore *g_sharedStore = NULL;
return; return;
} }
[databaseMirror removeObjectsAtIndexes:indexes];
__block int64_t total_count = 0; __block int64_t total_count = 0;
[indexes enumerateRangesUsingBlock:^(NSRange range, BOOL * _Nonnull stop) { [indexes enumerateRangesUsingBlock:^(NSRange range, BOOL * _Nonnull stop) {
@ -1665,6 +1679,14 @@ static SQLiteStore *g_sharedStore = NULL;
callback(-1); callback(-1);
} }
- (PlaylistEntry *)playlistGetCachedItem:(int64_t)index
{
if (index >= 0 && index < [databaseMirror count])
return [databaseMirror objectAtIndex:index];
else
return nil;
}
- (PlaylistEntry *)playlistGetItem:(int64_t)index - (PlaylistEntry *)playlistGetItem:(int64_t)index
{ {
PlaylistEntry *entry = [[PlaylistEntry alloc] init]; PlaylistEntry *entry = [[PlaylistEntry alloc] init];
@ -1687,8 +1709,10 @@ static SQLiteStore *g_sharedStore = NULL;
if (rc == SQLITE_ROW) if (rc == SQLITE_ROW)
{ {
int64_t trackId = sqlite3_column_int64(st, select_playlist_out_track_id); int64_t trackId = sqlite3_column_int64(st, select_playlist_out_track_id);
int64_t entryId = sqlite3_column_int64(st, select_playlist_out_entry_id);
entry = [self getTrack:trackId]; entry = [self getTrack:trackId];
[entry setIndex:index]; [entry setIndex:index];
[entry setEntryId:entryId];
} }
sqlite3_reset(st); sqlite3_reset(st);
@ -1836,73 +1860,33 @@ static SQLiteStore *g_sharedStore = NULL;
callback(0); callback(0);
double progress = 0; double progress = 0;
double progressstep = 50.0 / (double)(count); double progressstep = 100.0 / (double)(count);
NSMutableArray * entryIds = [[NSMutableArray alloc] init]; sqlite3_stmt *st = stmt[stmt_update_playlist];
NSMutableArray * entryIndexes = [[NSMutableArray alloc] init];
NSMutableArray * trackIds = [[NSMutableArray alloc] init];
sqlite3_stmt *st = stmt[stmt_select_playlist_all]; for (size_t i = 0; i < count; ++i)
int rc;
if (sqlite3_reset(st) ||
(rc = sqlite3_step(st)) != SQLITE_ROW)
{ {
callback(-1); PlaylistEntry * newpe = [entries objectAtIndex:i];
return; PlaylistEntry * oldpe = [databaseMirror objectAtIndex:i];
}
do
{
int64_t entryId = sqlite3_column_int64(st, select_playlist_all_out_entry_id);
int64_t entryIndex = sqlite3_column_int64(st, select_playlist_all_out_entry_index);
int64_t trackId = sqlite3_column_int64(st, select_playlist_all_out_track_id);
[entryIds addObject:[NSNumber numberWithInteger:entryId]];
[entryIndexes addObject:[NSNumber numberWithInteger:entryIndex]];
[trackIds addObject:[NSNumber numberWithInteger:trackId]];
rc = sqlite3_step(st);
progress += progressstep;
callback(progress);
}
while (rc == SQLITE_ROW);
sqlite3_reset(st);
progress = 50;
callback(progress);
st = stmt[stmt_update_playlist];
int64_t i = 0;
for (PlaylistEntry *entry in entries)
{
int64_t entryId = [[entryIds objectAtIndex:i] integerValue];
int64_t entryIndex = [[entryIndexes objectAtIndex:i] integerValue];
int64_t trackId = [[trackIds objectAtIndex:i] integerValue];
++i;
progress += progressstep;
if ([entry index] == entryIndex && progress += progressstep;
[entry dbIndex] == trackId)
continue;
if (sqlite3_reset(st) || if (([oldpe index] != i ||
sqlite3_bind_int64(st, update_playlist_in_entry_index, [entry index]) || [oldpe dbIndex] != [newpe dbIndex]) &&
sqlite3_bind_int64(st, update_playlist_in_track_id, [entry dbIndex]) || [oldpe entryId] == [newpe entryId]) {
sqlite3_bind_int64(st, update_playlist_in_id, entryId) ||
sqlite3_step(st) != SQLITE_DONE) if (sqlite3_reset(st) ||
{ sqlite3_bind_int64(st, update_playlist_in_id, [oldpe entryId]) ||
callback(-1); sqlite3_bind_int64(st, update_playlist_in_entry_index, i) ||
return; sqlite3_bind_int64(st, update_playlist_in_track_id, [newpe dbIndex]) ||
sqlite3_step(st) != SQLITE_ROW ||
sqlite3_reset(st))
{
callback(-1);
return;
}
callback(progress);
} }
callback(progress);
} }
sqlite3_reset(st); sqlite3_reset(st);