Significantly reduce memory usage all around

Added a string dictionary for deduplication of metadata, and actually
initialize both it and the art dictionary on startup, so they actually
work like they should.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
CQTexperiment
Christopher Snowhill 2022-02-16 16:57:47 -08:00
parent c242d53200
commit 3de43b55a7
3 changed files with 91 additions and 40 deletions

View File

@ -460,6 +460,7 @@
[self setMetadataLoaded:YES]; [self setMetadataLoaded:YES];
} }
// Now we duplicate the object to a new handle, but merely reference the same data
- (id)copyWithZone:(NSZone *)zone { - (id)copyWithZone:(NSZone *)zone {
PlaylistEntry *pe = [[[self class] allocWithZone:zone] init]; PlaylistEntry *pe = [[[self class] allocWithZone:zone] init];
@ -479,22 +480,22 @@
pe->queuePosition = queuePosition; pe->queuePosition = queuePosition;
pe->error = error; pe->error = error;
pe->errorMessage = [errorMessage copyWithZone:zone]; pe->errorMessage = errorMessage;
pe->URL = [URL copyWithZone:zone]; pe->URL = URL;
pe->artist = [artist copyWithZone:zone]; pe->artist = artist;
pe->albumartist = [albumartist copyWithZone:zone]; pe->albumartist = albumartist;
pe->album = [album copyWithZone:zone]; pe->album = album;
pe->title = [title copyWithZone:zone]; pe->title = title;
pe->genre = [genre copyWithZone:zone]; pe->genre = genre;
pe->year = [year copyWithZone:zone]; pe->year = year;
pe->track = [track copyWithZone:zone]; pe->track = track;
pe->disc = [disc copyWithZone:zone]; pe->disc = disc;
pe->cuesheet = [cuesheet copyWithZone:zone]; pe->cuesheet = cuesheet;
pe->albumArtInternal = albumArtInternal; // Only allocated item not duplicated pe->albumArtInternal = albumArtInternal;
pe->replayGainAlbumGain = replayGainAlbumGain; pe->replayGainAlbumGain = replayGainAlbumGain;
pe->replayGainAlbumPeak = replayGainAlbumPeak; pe->replayGainAlbumPeak = replayGainAlbumPeak;
@ -513,11 +514,11 @@
pe->Unsigned = Unsigned; pe->Unsigned = Unsigned;
pe->sampleRate = sampleRate; pe->sampleRate = sampleRate;
pe->codec = [codec copyWithZone:zone]; pe->codec = codec;
pe->endian = [endian copyWithZone:zone]; pe->endian = endian;
pe->encoding = [encoding copyWithZone:zone]; pe->encoding = encoding;
pe->seekable = seekable; pe->seekable = seekable;

View File

@ -20,6 +20,7 @@
@private @private
NSMutableArray *databaseMirror; NSMutableArray *databaseMirror;
NSMutableDictionary *artTable; NSMutableDictionary *artTable;
NSMutableDictionary *stringTable;
} }
@property(nonatomic, readwrite) NSString *databasePath; @property(nonatomic, readwrite) NSString *databasePath;

View File

@ -511,7 +511,7 @@ NSURL *urlForPath(NSString *path) {
} }
@interface SQLiteStore (Private) @interface SQLiteStore (Private)
- (int64_t)addString:(NSString *)string; - (int64_t)addString:(NSString **)string;
- (NSString *)getString:(int64_t)stringId; - (NSString *)getString:(int64_t)stringId;
- (void)removeString:(int64_t)stringId; - (void)removeString:(int64_t)stringId;
- (int64_t)addArt:(NSData *)art; - (int64_t)addArt:(NSData *)art;
@ -668,6 +668,8 @@ static SQLiteStore *g_sharedStore = NULL;
size_t count = [self playlistGetCount]; size_t count = [self playlistGetCount];
databaseMirror = [[NSMutableArray alloc] init]; databaseMirror = [[NSMutableArray alloc] init];
artTable = [[NSMutableDictionary alloc] init];
stringTable = [[NSMutableDictionary alloc] init];
for(size_t i = 0; i < count; ++i) { for(size_t i = 0; i < count; ++i) {
PlaylistEntry *pe = [self playlistGetItem:i]; PlaylistEntry *pe = [self playlistGetItem:i];
@ -690,12 +692,12 @@ static SQLiteStore *g_sharedStore = NULL;
} }
} }
- (int64_t)addString:(NSString *)string { - (int64_t)addString:(NSString **)string {
if(!string || [string length] == 0) { if(!*string || [*string length] == 0) {
return -1; return -1;
} }
const char *str = [string UTF8String]; const char *str = [*string UTF8String];
uint64_t len = strlen(str); // SQLite expects number of bytes, not characters uint64_t len = strlen(str); // SQLite expects number of bytes, not characters
sqlite3_stmt *st = stmt[stmt_select_string]; sqlite3_stmt *st = stmt[stmt_select_string];
@ -732,6 +734,8 @@ static SQLiteStore *g_sharedStore = NULL;
ret = sqlite3_last_insert_rowid(g_database); ret = sqlite3_last_insert_rowid(g_database);
refcount = 1; refcount = 1;
[stringTable setObject:*string forKey:[[NSNumber numberWithInteger:ret] stringValue]];
} else { } else {
st = stmt[stmt_bump_string]; st = stmt[stmt_bump_string];
@ -741,6 +745,8 @@ static SQLiteStore *g_sharedStore = NULL;
sqlite3_reset(st)) { sqlite3_reset(st)) {
return -1; return -1;
} }
*string = [stringTable objectForKey:[[NSNumber numberWithInteger:ret] stringValue]];
} }
return ret; return ret;
@ -750,6 +756,9 @@ static SQLiteStore *g_sharedStore = NULL;
if(stringId < 0) if(stringId < 0)
return @""; return @"";
NSString *ret = [stringTable objectForKey:[[NSNumber numberWithInteger:stringId] stringValue]];
if(ret) return ret;
sqlite3_stmt *st = stmt[stmt_select_string_value]; sqlite3_stmt *st = stmt[stmt_select_string_value];
if(sqlite3_reset(st) || if(sqlite3_reset(st) ||
@ -764,7 +773,7 @@ static SQLiteStore *g_sharedStore = NULL;
return @""; return @"";
} }
NSString *ret = @""; ret = @"";
if(rc == SQLITE_ROW) { if(rc == SQLITE_ROW) {
const unsigned char *str = sqlite3_column_text(st, select_string_value_out_value); const unsigned char *str = sqlite3_column_text(st, select_string_value_out_value);
@ -817,6 +826,8 @@ static SQLiteStore *g_sharedStore = NULL;
sqlite3_reset(st)) { sqlite3_reset(st)) {
return; return;
} }
[stringTable removeObjectForKey:[[NSNumber numberWithInteger:stringId] stringValue]];
} else { } else {
st = stmt[stmt_pop_string]; st = stmt[stmt_pop_string];
@ -978,7 +989,7 @@ static SQLiteStore *g_sharedStore = NULL;
NSURL *url = [track URL]; NSURL *url = [track URL];
NSString *urlString = [url absoluteString]; NSString *urlString = [url absoluteString];
int64_t urlId = [self addString:urlString]; int64_t urlId = [self addString:&urlString];
sqlite3_stmt *st = stmt[stmt_select_track]; sqlite3_stmt *st = stmt[stmt_select_track];
@ -1005,14 +1016,31 @@ static SQLiteStore *g_sharedStore = NULL;
sqlite3_reset(stmt[stmt_select_string]); sqlite3_reset(stmt[stmt_select_string]);
if(rc != SQLITE_ROW) { if(rc != SQLITE_ROW) {
int64_t albumId = [self addString:[track album]]; NSString *temp;
int64_t albumartistId = [self addString:[track albumartist]]; temp = [track album];
int64_t artistId = [self addString:[track artist]]; int64_t albumId = [self addString:&temp];
int64_t titleId = [self addString:[track rawTitle]]; [track setAlbum:temp];
int64_t genreId = [self addString:[track genre]]; temp = [track albumartist];
int64_t codecId = [self addString:[track codec]]; int64_t albumartistId = [self addString:&temp];
int64_t cuesheetId = [self addString:[track cuesheet]]; [track setAlbumartist:temp];
int64_t encodingId = [self addString:[track encoding]]; temp = [track artist];
int64_t artistId = [self addString:&temp];
[track setArtist:temp];
temp = [track rawTitle];
int64_t titleId = [self addString:&temp];
[track setTitle:temp];
temp = [track genre];
int64_t genreId = [self addString:&temp];
[track setGenre:temp];
temp = [track codec];
int64_t codecId = [self addString:&temp];
[track setCodec:temp];
temp = [track cuesheet];
int64_t cuesheetId = [self addString:&temp];
[track setCuesheet:temp];
temp = [track encoding];
int64_t encodingId = [self addString:&temp];
[track setEncoding:temp];
int64_t trackNr = [[track track] intValue] | (((uint64_t)[[track disc] intValue]) << 32); int64_t trackNr = [[track track] intValue] | (((uint64_t)[[track disc] intValue]) << 32);
int64_t year = [[track year] intValue]; int64_t year = [[track year] intValue];
int64_t unsignedFmt = [track Unsigned]; int64_t unsignedFmt = [track Unsigned];
@ -1021,7 +1049,9 @@ static SQLiteStore *g_sharedStore = NULL;
int64_t bitspersample = [track bitsPerSample]; int64_t bitspersample = [track bitsPerSample];
int64_t channels = [track channels]; int64_t channels = [track channels];
int64_t channelConfig = [track channelConfig]; int64_t channelConfig = [track channelConfig];
int64_t endianId = [self addString:[track endian]]; temp = [track endian];
int64_t endianId = [self addString:&temp];
[track setEndian:temp];
int64_t floatingpoint = [track floatingPoint]; int64_t floatingpoint = [track floatingPoint];
int64_t totalframes = [track totalFrames]; int64_t totalframes = [track totalFrames];
int64_t metadataloaded = [track metadataLoaded]; int64_t metadataloaded = [track metadataLoaded];
@ -1113,7 +1143,7 @@ static SQLiteStore *g_sharedStore = NULL;
NSURL *url = [track URL]; NSURL *url = [track URL];
NSString *urlString = [url absoluteString]; NSString *urlString = [url absoluteString];
int64_t urlId = [self addString:urlString]; int64_t urlId = [self addString:&urlString];
sqlite3_stmt *st = stmt[stmt_select_track]; sqlite3_stmt *st = stmt[stmt_select_track];
@ -1201,14 +1231,31 @@ static SQLiteStore *g_sharedStore = NULL;
sqlite3_reset(st); sqlite3_reset(st);
{ {
int64_t albumId = [self addString:[track album]]; NSString *temp;
int64_t albumartistId = [self addString:[track albumartist]]; temp = [track album];
int64_t artistId = [self addString:[track artist]]; int64_t albumId = [self addString:&temp];
int64_t titleId = [self addString:[track rawTitle]]; [track setAlbum:temp];
int64_t genreId = [self addString:[track genre]]; temp = [track albumartist];
int64_t codecId = [self addString:[track codec]]; int64_t albumartistId = [self addString:&temp];
int64_t cuesheetId = [self addString:[track cuesheet]]; [track setAlbumartist:temp];
int64_t encodingId = [self addString:[track encoding]]; temp = [track artist];
int64_t artistId = [self addString:&temp];
[track setArtist:temp];
temp = [track rawTitle];
int64_t titleId = [self addString:&temp];
[track setTitle:temp];
temp = [track genre];
int64_t genreId = [self addString:&temp];
[track setGenre:temp];
temp = [track codec];
int64_t codecId = [self addString:&temp];
[track setCodec:temp];
temp = [track cuesheet];
int64_t cuesheetId = [self addString:&temp];
[track setCuesheet:temp];
temp = [track encoding];
int64_t encodingId = [self addString:&temp];
[track setEncoding:temp];
int64_t trackNr = [[track track] intValue] | (((uint64_t)[[track disc] intValue]) << 32); int64_t trackNr = [[track track] intValue] | (((uint64_t)[[track disc] intValue]) << 32);
int64_t year = [[track year] intValue]; int64_t year = [[track year] intValue];
int64_t unsignedFmt = [track Unsigned]; int64_t unsignedFmt = [track Unsigned];
@ -1217,7 +1264,9 @@ static SQLiteStore *g_sharedStore = NULL;
int64_t bitspersample = [track bitsPerSample]; int64_t bitspersample = [track bitsPerSample];
int64_t channels = [track channels]; int64_t channels = [track channels];
int64_t channelConfig = [track channelConfig]; int64_t channelConfig = [track channelConfig];
int64_t endianId = [self addString:[track endian]]; temp = [track endian];
int64_t endianId = [self addString:&temp];
[track setEndian:temp];
int64_t floatingpoint = [track floatingPoint]; int64_t floatingpoint = [track floatingPoint];
int64_t totalframes = [track totalFrames]; int64_t totalframes = [track totalFrames];
int64_t metadataloaded = [track metadataLoaded]; int64_t metadataloaded = [track metadataLoaded];