1 /* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 // vim: ft=cpp:expandtab:ts=8:sw=4:softtabstop=4:
3 /*======
4 This file is part of PerconaFT.
5 
6 
7 Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved.
8 
9     PerconaFT is free software: you can redistribute it and/or modify
10     it under the terms of the GNU General Public License, version 2,
11     as published by the Free Software Foundation.
12 
13     PerconaFT is distributed in the hope that it will be useful,
14     but WITHOUT ANY WARRANTY; without even the implied warranty of
15     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16     GNU General Public License for more details.
17 
18     You should have received a copy of the GNU General Public License
19     along with PerconaFT.  If not, see <http://www.gnu.org/licenses/>.
20 
21 ----------------------------------------
22 
23     PerconaFT is free software: you can redistribute it and/or modify
24     it under the terms of the GNU Affero General Public License, version 3,
25     as published by the Free Software Foundation.
26 
27     PerconaFT is distributed in the hope that it will be useful,
28     but WITHOUT ANY WARRANTY; without even the implied warranty of
29     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
30     GNU Affero General Public License for more details.
31 
32     You should have received a copy of the GNU Affero General Public License
33     along with PerconaFT.  If not, see <http://www.gnu.org/licenses/>.
34 
35 ----------------------------------------
36 
37    Licensed under the Apache License, Version 2.0 (the "License");
38    you may not use this file except in compliance with the License.
39    You may obtain a copy of the License at
40 
41        http://www.apache.org/licenses/LICENSE-2.0
42 
43    Unless required by applicable law or agreed to in writing, software
44    distributed under the License is distributed on an "AS IS" BASIS,
45    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
46    See the License for the specific language governing permissions and
47    limitations under the License.
48 ======= */
49 
50 #ident \
51     "Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved."
52 
53 #pragma once
54 
55 #include <string.h>
56 
57 #include "../db.h"
58 #include "../portability/memory.h"
59 #include "../util/dbt.h"
60 
61 typedef int (*ft_compare_func)(void *arg, const DBT *a, const DBT *b);
62 
63 int toku_keycompare(const void *key1, size_t key1len, const void *key2,
64                     size_t key2len);
65 
66 int toku_builtin_compare_fun(const DBT *, const DBT *)
67     __attribute__((__visibility__("default")));
68 
69 namespace toku {
70 
71 // a comparator object encapsulates the data necessary for
72 // comparing two keys in a fractal tree. it further understands
73 // that points may be positive or negative infinity.
74 
75 class comparator {
init(ft_compare_func cmp,void * cmp_arg,uint8_t memcmp_magic)76   void init(ft_compare_func cmp, void *cmp_arg, uint8_t memcmp_magic) {
77     _cmp = cmp;
78     _cmp_arg = cmp_arg;
79     _memcmp_magic = memcmp_magic;
80   }
81 
82  public:
83   // This magic value is reserved to mean that the magic has not been set.
84   static const uint8_t MEMCMP_MAGIC_NONE = 0;
85 
86   void create(ft_compare_func cmp, void *cmp_arg,
87               uint8_t memcmp_magic = MEMCMP_MAGIC_NONE) {
88     init(cmp, cmp_arg, memcmp_magic);
89   }
90 
91   // inherit the attributes of another comparator, but keep our own
92   // copy of fake_db that is owned separately from the one given.
inherit(const comparator & cmp)93   void inherit(const comparator &cmp) {
94     invariant_notnull(cmp._cmp);
95     init(cmp._cmp, cmp._cmp_arg, cmp._memcmp_magic);
96   }
97 
98   // like inherit, but doesn't require that the this comparator
99   // was already created
create_from(const comparator & cmp)100   void create_from(const comparator &cmp) { inherit(cmp); }
101 
destroy()102   void destroy() {}
103 
get_compare_func()104   ft_compare_func get_compare_func() const { return _cmp; }
105 
get_memcmp_magic()106   uint8_t get_memcmp_magic() const { return _memcmp_magic; }
107 
valid()108   bool valid() const { return _cmp != nullptr; }
109 
dbt_has_memcmp_magic(const DBT * dbt)110   inline bool dbt_has_memcmp_magic(const DBT *dbt) const {
111     return *reinterpret_cast<const char *>(dbt->data) == _memcmp_magic;
112   }
113 
operator()114   int operator()(const DBT *a, const DBT *b) const {
115     if (__builtin_expect(toku_dbt_is_infinite(a) || toku_dbt_is_infinite(b),
116                          0)) {
117       return toku_dbt_infinite_compare(a, b);
118     } else if (_memcmp_magic != MEMCMP_MAGIC_NONE
119                // If `a' has the memcmp magic..
120                && dbt_has_memcmp_magic(a)
121                // ..then we expect `b' to also have the memcmp magic
122                && __builtin_expect(dbt_has_memcmp_magic(b), 1)) {
123       assert(0);  // psergey: this branch should not be taken.
124       return toku_builtin_compare_fun(a, b);
125     } else {
126       // yikes, const sadness here
127       return _cmp(_cmp_arg, a, b);
128     }
129   }
130 
131  private:
132   ft_compare_func _cmp;
133   void *_cmp_arg;
134 
135   uint8_t _memcmp_magic;
136 };
137 
138 } /* namespace toku */
139