1 /* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /*
3  *     Copyright 2017 Couchbase, Inc
4  *
5  *   Licensed under the Apache License, Version 2.0 (the "License");
6  *   you may not use this file except in compliance with the License.
7  *   You may obtain a copy of the License at
8  *
9  *       http://www.apache.org/licenses/LICENSE-2.0
10  *
11  *   Unless required by applicable law or agreed to in writing, software
12  *   distributed under the License is distributed on an "AS IS" BASIS,
13  *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *   See the License for the specific language governing permissions and
15  *   limitations under the License.
16  */
17 
18 #pragma once
19 
20 #include "item.h"
21 
22 #include <memcached/dockey.h>
23 #include <memcached/engine_common.h>
24 #include <platform/sized_buffer.h>
25 
26 #include <memory>
27 #include <string>
28 #include <unordered_map>
29 
30 class SystemEventMessage;
31 
32 namespace Collections {
33 
34 class Filter;
35 
36 namespace VB {
37 
38 class Manifest;
39 
40 /**
41  * The VB filter is used to decide if keys on a DCP stream should be sent
42  * or dropped.
43  *
44  * A filter is built from the Collections::Filter that was established when
45  * the producer was opened. During the time the producer was opened and a
46  * stream is requested, filtered collections may have been deleted, so the
47  * ::VB::Filter becomes the intersection of the producer's filter and the
48  * open collections within the manifest.
49  *
50  * Note: There is no locking on a VB::Filter as at the moment it is constructed
51  * and then is not mutable.
52  */
53 
54 class Filter {
55 public:
56     /**
57      * Construct a Collections::VB::Filter using the producer's
58      * Collections::Filter and the vbucket's collections manifest.
59      *
60      * If the producer's filter is configured to filter collections then the
61      * resulting object will filter the intersection filter:manifest
62      * collections. The constructor will log when it finds it must drop a
63      * collection
64      *
65      * If the producer's filter is effectively a passthrough
66      * (allowAllCollections returns true) then so will the resulting VB filter.
67      *
68      * @param filter The producer's filter that the client configured.
69      * @param manifest The vbucket's collection manifest.
70      */
71     Filter(const ::Collections::Filter& filter,
72            const ::Collections::VB::Manifest& manifest);
73 
74     /**
75      * Check the item and if required, update the filter.
76      * If the item represents a collection deletion and this filter matches the
77      * collection, we must update the filter so that no more matching items
78      * would be allowed.
79      *
80      * @param item an Item to be processed.
81      * @return if the Item is allowed to be sent on the DcpStream
82      */
checkAndUpdate(const Item& item)83     bool checkAndUpdate(const Item& item) {
84         // passthrough, everything is allowed.
85         if (passthrough) {
86             return true;
87         }
88 
89         // The presence of $default is a simple check against defaultAllowed
90         if (item.getKey().getDocNamespace() ==
91                     DocNamespace::DefaultCollection &&
92             defaultAllowed) {
93             return true;
94         }
95         // More complex checks needed...
96         return checkAndUpdateSlow(item);
97     }
98 
99     /**
100      * @return if the filter is empty
101      */
102     bool empty() const;
103 
104     /**
105      * Add statistics for this filter, currently just depicts the object's state
106      */
107     void addStats(ADD_STAT add_stat,
108                   const void* c,
109                   const std::string& prefix,
110                   uint16_t vb) const;
111 
112     /**
113      * Dump this to std::cerr
114      */
115     void dump() const;
116 
117 protected:
118     /**
119      * Does the filter allow the system event? I.e. a "meat,dairy" filter
120      * shouldn't allow delete events for the "fruit" collection.
121      *
122      * @param item a SystemEventMessage to check
123      * @param return true if the filter says this event should be allowed
124      */
125     bool allowSystemEvent(const Item& item) const;
126 
127     /// Non-inline, slow path of checkAndUpdate().
128     bool checkAndUpdateSlow(const Item& item);
129 
130     /**
131      * Remove the collection of the item from the filter
132      */
133     void remove(const Item& item);
134 
135     using Container = ::std::unordered_map<cb::const_char_buffer,
136                                            std::unique_ptr<std::string>>;
137     Container filter;
138     bool defaultAllowed;
139     bool passthrough;
140     bool systemEventsAllowed;
141     std::string separator;
142 
143     friend std::ostream& operator<<(std::ostream& os, const Filter& filter);
144 };
145 
146 std::ostream& operator<<(std::ostream& os, const Filter& filter);
147 
148 } // end namespace VB
149 } // end namespace Collections
150