id3fs-index: removed unused entries when reindexing
authorIan Beckwith <ianb@erislabs.net>
Fri, 1 Oct 2010 19:55:37 +0000 (20:55 +0100)
committerIan Beckwith <ianb@erislabs.net>
Fri, 1 Oct 2010 19:55:37 +0000 (20:55 +0100)
bin/id3fs-index
lib/ID3FS/DB.pm

index 89f6f12..9493f7c 100755 (executable)
@@ -16,6 +16,7 @@ my $basedir=undef;
 my $dbpath=undef;
 my $list=0;
 my @extensions=qw(mp3 flac ogg);
+my $files_pruned;
 
 Configure(qw(bundling no_ignore_case));
 my $optret=GetOptions(
@@ -44,10 +45,16 @@ else
 {
     $db->last_update(time());
 
+    my $directories_pruned=$db->prune_directories();
     while(my $path=shift)
     {
        File::Find::find( {wanted => \&wanted, follow => 1, no_chdir => 1}, $path);
     }
+    if($files_pruned || $directories_pruned)
+    {
+       print "Removing data from pruned files\n" if $verbose;
+       $db->remove_unused();
+    }
 }
 
 sub wanted
@@ -57,6 +64,7 @@ sub wanted
     if(-d)
     {
        print("$_\n") if $verbose;
+       prune($_);
     }
     elsif(-f && scalar(grep({ $ext eq lc($_);} @extensions)))
     {
@@ -65,6 +73,33 @@ sub wanted
     }
 }
 
+
+sub prune
+{
+    my $dir=shift;
+    return unless(opendir(DIR, $dir));
+    print "Pruning $dir\n";
+    my @oldfiles=$db->files_in($dir);
+    my @newfiles=grep { !/^\.\.?$/; } readdir(DIR);
+    closedir(DIR);
+    @oldfiles=sort @oldfiles;
+    @newfiles=sort @newfiles;
+    my %hash;
+    @hash{@newfiles}=();
+    for my $file (@oldfiles)
+    {
+       unless(exists($hash{$file}))
+       {
+           # FIXME: add path, rebasify
+           $files_pruned=1;
+           $db->unindex($file);
+       }
+    }
+}
+
+
+
+
 sub list_tags
 {
     my($db)=@_;
index b4c95aa..5f08a04 100644 (file)
@@ -520,6 +520,91 @@ sub tag_has_values
     return $rows;
 }
 
+sub files_in
+{
+    my ($self, $dir)=@_;
+    $dir=~s/^$self->{base}\/?//;
+    print "Munged dir: $dir\n";
+    my $sql=("SELECT files.name FROM files\n" .
+            "INNER JOIN paths ON files.paths_id=paths.id\n" .
+            "WHERE paths.name=?\n");
+    my $files=$self->cmd_rows($sql, $dir);
+    return(map { $_->[0]; } @$files);
+}
+
+sub prune_directories
+{
+    my($self)=@_;
+    my $sql=("SELECT name, id FROM paths ORDER BY name\n");
+    my $pathsref=$self->cmd_rows($sql);
+    my @ids=();
+    for my $pathpair (@$pathsref)
+    {
+       my($path, $id)=@$pathpair;
+       my $fullpath="$self->{absbase}/$path";
+       print "PRUNING PATH $fullpath: ";
+       unless(-d $fullpath)
+       {
+           push(@ids, $id)
+       }
+    }
+    $self->prune_paths(@ids);
+    return scalar(@ids);
+}
+
+sub prune_paths
+{
+    my($self, @ids)=@_;
+    my $sql=("DELETE FROM files WHERE paths_id IN (\n\t" .
+            join(', ', map { "\"$_\""; } @ids). "\n\t)");
+    print "SQL: \n", $sql, "\n";
+    $self->cmd($sql);
+}
+
+sub remove_unused
+{
+    my($self)=@_;
+    my $sql=<<'EOT';
+   DELETE FROM artists WHERE id IN (
+       SELECT artists.id FROM artists
+       LEFT JOIN files ON files.artists_id=artists.id
+       WHERE files.id IS NULL);
+
+   DELETE FROM albums WHERE id IN (
+       SELECT albums.id FROM albums
+       LEFT JOIN files ON files.albums_id=albums.id
+       WHERE files.id IS NULL);
+
+   DELETE FROM paths WHERE id IN (
+       SELECT paths.id FROM paths
+       LEFT JOIN files ON files.paths_id=paths.id
+       WHERE files.id IS NULL);
+
+   DELETE FROM files_x_tags WHERE files_id IN (
+       SELECT files_x_tags.files_id FROM files_x_tags
+       LEFT JOIN files ON files.id=files_x_tags.files_id
+       WHERE files.id IS NULL);
+
+   DELETE FROM tags WHERE id IN (
+       SELECT tags.id FROM tags
+       LEFT JOIN files_x_tags ON files_x_tags.tags_id=tags.id
+       WHERE files_x_tags.files_id IS NULL);
+
+   DELETE FROM tags_x_tagvals WHERE tags_id IN (
+       SELECT tags_x_tagvals.tags_id FROM tags_x_tagvals
+       LEFT JOIN tags ON tags.id=tags_x_tagvals.tags_id
+       WHERE tags.id IS NULL);
+
+   DELETE FROM tagvals WHERE id IN (
+       SELECT tagvals.id FROM tagvals
+       LEFT JOIN tags_x_tagvals ON tags_x_tagvals.tagvals_id=tagvals.id
+       WHERE tags_x_tagvals.tagvals_id IS NULL);
+EOT
+    print "SQL: $sql\n";
+    my @sql=split(/\n\n/, $sql);
+    $self->cmd($_) for (@sql);
+}
+
 sub relation_exists
 {
     my ($self, $relname, $fields)=@_;
@@ -640,3 +725,4 @@ CREATE TABLE tags_x_tagvals (
     FOREIGN KEY(tags_id) REFERENCES tags(id) ON DELETE CASCADE ON UPDATE CASCADE,
     FOREIGN KEY(tagvals_id) REFERENCES tagvals(id) ON DELETE CASCADE ON UPDATE CASCADE
 );
+