summaryrefslogtreecommitdiffstats
path: root/Bugzilla/Bloomfilter.pm
diff options
context:
space:
mode:
Diffstat (limited to 'Bugzilla/Bloomfilter.pm')
-rw-r--r--Bugzilla/Bloomfilter.pm67
1 files changed, 67 insertions, 0 deletions
diff --git a/Bugzilla/Bloomfilter.pm b/Bugzilla/Bloomfilter.pm
new file mode 100644
index 000000000..0d329b2ea
--- /dev/null
+++ b/Bugzilla/Bloomfilter.pm
@@ -0,0 +1,67 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# This Source Code Form is "Incompatible With Secondary Licenses", as
+# defined by the Mozilla Public License, v. 2.0.
+
+package Bugzilla::Bloomfilter;
+
+use 5.10.1;
+use strict;
+use warnings;
+
+use Bugzilla::Constants;
+use Algorithm::BloomFilter;
+use File::Temp qw(tempfile);
+
+sub _new_bloom_filter {
+ my ($n) = @_;
+ my $p = 0.01;
+ my $m = $n * abs(log $p) / log(2) ** 2;
+ my $k = $m / $n * log(2);
+ return Algorithm::BloomFilter->new($m, $k);
+}
+
+sub _filename {
+ my ($name) = @_;
+
+ my $datadir = bz_locations->{datadir};
+ return sprintf("%s/%s.bloom", $datadir, $name);
+}
+
+sub populate {
+ my ($class, $name, $items) = @_;
+ my $memcached = Bugzilla->memcached;
+
+ my $filter = _new_bloom_filter(@$items + 0);
+ foreach my $item (@$items) {
+ $filter->add($item);
+ }
+
+ my ($fh, $filename) = tempfile( "${name}XXXXXX", DIR => bz_locations->{datadir}, UNLINK => 0);
+ binmode $fh, ':bytes';
+ print $fh $filter->serialize;
+ close $fh;
+ rename($filename, _filename($name)) or die "failed to rename $filename: $!";
+ $memcached->clear_bloomfilter({name => $name});
+}
+
+sub lookup {
+ my ($class, $name) = @_;
+ my $memcached = Bugzilla->memcached;
+ my $filename = _filename($name);
+ my $filter_data = $memcached->get_bloomfilter( { name => $name } );
+
+ if (!$filter_data && -f $filename) {
+ open my $fh, '<:bytes', $filename;
+ local $/ = undef;
+ $filter_data = <$fh>;
+ close $fh;
+ $memcached->set_bloomfilter({ name => $name, filter => $filter_data });
+ }
+
+ return Algorithm::BloomFilter->deserialize($filter_data);
+}
+
+1;