def _filter(self, environ, params):
        """
        Performs final filtering of the request to determine if this
        limit applies.  Returns False if the limit does not apply or
        if the call should not be limited, or True to apply the limit.
        """

        # Search for required query arguments
        if self.queries:
            # No query string available
            if 'QUERY_STRING' not in environ:
                return False

            # Extract the list of provided query arguments from the
            # QUERY_STRING
            available = set(qstr.partition('=')[0] for qstr in
                            environ['QUERY_STRING'].split('&'))

            # Check if we have the required query arguments
            required = set(self.queries)
            if not required.issubset(available):
                return False

        # Use only the parameters listed in use; we'll add the others
        # back later
        unused = {}
        for key, value in params.items():
            if key not in self.use:
                unused[key] = value

        # Do this in a separate step so we avoid changing a
        # dictionary during traversal
        for key in unused:
            del params[key]

        # First, we need to set up any additional params required to
        # get the bucket.  If the DeferLimit exception is thrown, no
        # further processing is performed.
        try:
            additional = self.filter(environ, params, unused) or {}
        except DeferLimit:
            return False

        # Compute the bucket key
        key = self.key(params)

        # Update the parameters...
        params.update(unused)
        params.update(additional)

        # Get the current time
        now = time.time()

        # Allow up to a minute to mutate the bucket record.  If no
        # bucket exists currently, this is essentially a no-op, and
        # the bucket won't expire anyway, once the update record is
        # pushed.
        self.db.expire(key, 60)

        # Push an update record
        update_uuid = str(uuid.uuid4())
        update = {
            'uuid': update_uuid,
            'update': {
                'params': params,
                'time': now,
            },
        }
        self.db.rpush(key, msgpack.dumps(update))

        # Now suck in the bucket
        records = self.db.lrange(key, 0, -1)
        loader = BucketLoader(self.bucket_class, self.db, self, key, records)

        # Determine if we should initialize the compactor algorithm on
        # this bucket
        if 'turnstile.conf' in environ:
            config = environ['turnstile.conf']['compactor']
            try:
                max_updates = int(config['max_updates'])
            except (KeyError, ValueError):
                max_updates = None
            try:
                max_age = int(config['max_age'])
            except (KeyError, ValueError):
                max_age = 600
            if max_updates and loader.need_summary(now, max_updates, max_age):
                # Add a summary record; we want to do this before
                # instructing the compactor to compact.  If we did the
                # compactor instruction first, and a crash occurred
                # before adding the summarize record, the lack of
                # quiesence could cause two compactor threads to run
                # on the same bucket, leading to a race condition that
                # could corrupt the bucket.  With this ordering, if a
                # crash occurs before the compactor instruction, the
                # maximum aging applied to summarize records will
                # cause this logic to eventually be retriggered, which
                # should allow the compactor instruction to be issued.
                summarize = dict(summarize=now, uuid=str(uuid.uuid4()))
                self.db.rpush(key, msgpack.dumps(summarize))

                # Instruct the compactor to compact this record
                compactor_key = config.get('compactor_key', 'compactor')
                self.db.zadd(compactor_key, int(math.ceil(now)), key)

        # Set the expire on the bucket
        self.db.expireat(key, loader.bucket.expire)

        # If we found a delay, store the particulars in the
        # environment; this will later be sorted and an error message
        # corresponding to the longest delay returned.
        if loader.delay is not None:
            environ.setdefault('turnstile.delay', [])
            environ['turnstile.delay'].append((loader.delay, self,
                                               loader.bucket))

        # Finally, if desired, add the bucket key to a desired
        # database set
        set_name = environ.get('turnstile.bucket_set')
        if set_name:
            self.db.zadd(set_name, loader.bucket.expire, key)

        # Should we continue the route scan?
        return not self.continue_scan