1 | /* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- */ |
2 | // vim: ft=cpp:expandtab:ts=8:sw=4:softtabstop=4: |
3 | #ident "$Id$" |
4 | /*====== |
5 | This file is part of PerconaFT. |
6 | |
7 | |
8 | Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved. |
9 | |
10 | PerconaFT is free software: you can redistribute it and/or modify |
11 | it under the terms of the GNU General Public License, version 2, |
12 | as published by the Free Software Foundation. |
13 | |
14 | PerconaFT is distributed in the hope that it will be useful, |
15 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
17 | GNU General Public License for more details. |
18 | |
19 | You should have received a copy of the GNU General Public License |
20 | along with PerconaFT. If not, see <http://www.gnu.org/licenses/>. |
21 | |
22 | ---------------------------------------- |
23 | |
24 | PerconaFT is free software: you can redistribute it and/or modify |
25 | it under the terms of the GNU Affero General Public License, version 3, |
26 | as published by the Free Software Foundation. |
27 | |
28 | PerconaFT is distributed in the hope that it will be useful, |
29 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
30 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
31 | GNU Affero General Public License for more details. |
32 | |
33 | You should have received a copy of the GNU Affero General Public License |
34 | along with PerconaFT. If not, see <http://www.gnu.org/licenses/>. |
35 | ======= */ |
36 | |
37 | #ident "Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved." |
38 | |
39 | #include <my_global.h> |
40 | #include "ft/ft.h" |
41 | #include "ft/ft-internal.h" |
42 | #include "ft/le-cursor.h" |
43 | #include "ft/cursor.h" |
44 | |
45 | // A LE_CURSOR is a special purpose FT_CURSOR that: |
46 | // - enables prefetching |
47 | // - does not perform snapshot reads. it reads everything, including uncommitted. |
48 | // |
49 | // A LE_CURSOR is good for scanning a FT from beginning to end. Useful for hot indexing. |
50 | |
51 | struct le_cursor { |
52 | FT_CURSOR ft_cursor; |
53 | bool neg_infinity; // true when the le cursor is positioned at -infinity (initial setting) |
54 | bool pos_infinity; // true when the le cursor is positioned at +infinity (when _next returns DB_NOTFOUND) |
55 | }; |
56 | |
57 | int |
58 | toku_le_cursor_create(LE_CURSOR *le_cursor_result, FT_HANDLE ft_handle, TOKUTXN txn) { |
59 | int result = 0; |
60 | LE_CURSOR MALLOC(le_cursor); |
61 | if (le_cursor == NULL) { |
62 | result = get_error_errno(); |
63 | } |
64 | else { |
65 | result = toku_ft_cursor(ft_handle, &le_cursor->ft_cursor, txn, false, false); |
66 | if (result == 0) { |
67 | // TODO move the leaf mode to the ft cursor constructor |
68 | toku_ft_cursor_set_leaf_mode(le_cursor->ft_cursor); |
69 | le_cursor->neg_infinity = false; |
70 | le_cursor->pos_infinity = true; |
71 | } |
72 | } |
73 | |
74 | if (result == 0) { |
75 | *le_cursor_result = le_cursor; |
76 | } else { |
77 | toku_free(le_cursor); |
78 | } |
79 | |
80 | return result; |
81 | } |
82 | |
83 | void toku_le_cursor_close(LE_CURSOR le_cursor) { |
84 | toku_ft_cursor_close(le_cursor->ft_cursor); |
85 | toku_free(le_cursor); |
86 | } |
87 | |
88 | // Move to the next leaf entry under the LE_CURSOR |
89 | // Success: returns zero, calls the getf callback with the getf_v parameter |
90 | // Failure: returns a non-zero error number |
91 | int |
92 | toku_le_cursor_next(LE_CURSOR le_cursor, FT_GET_CALLBACK_FUNCTION getf, void *getf_v) { |
93 | int result; |
94 | if (le_cursor->neg_infinity) { |
95 | result = DB_NOTFOUND; |
96 | } else { |
97 | le_cursor->pos_infinity = false; |
98 | // TODO replace this with a non deprecated function. Which? |
99 | result = toku_ft_cursor_get(le_cursor->ft_cursor, NULL, getf, getf_v, DB_PREV); |
100 | if (result == DB_NOTFOUND) { |
101 | le_cursor->neg_infinity = true; |
102 | } |
103 | } |
104 | return result; |
105 | } |
106 | |
107 | bool |
108 | toku_le_cursor_is_key_greater_or_equal(LE_CURSOR le_cursor, const DBT *key) { |
109 | bool result; |
110 | if (le_cursor->neg_infinity) { |
111 | result = true; // all keys are greater than -infinity |
112 | } else if (le_cursor->pos_infinity) { |
113 | result = false; // all keys are less than +infinity |
114 | } else { |
115 | FT ft = le_cursor->ft_cursor->ft_handle->ft; |
116 | // get the current position from the cursor and compare it to the given key. |
117 | int r = ft->cmp(&le_cursor->ft_cursor->key, key); |
118 | if (r <= 0) { |
119 | result = true; // key is right of the cursor key |
120 | } else { |
121 | result = false; // key is at or left of the cursor key |
122 | } |
123 | } |
124 | return result; |
125 | } |
126 | |
127 | void |
128 | toku_le_cursor_update_estimate(LE_CURSOR le_cursor, DBT* estimate) { |
129 | // don't handle these edge cases, not worth it. |
130 | // estimate stays same |
131 | if (le_cursor->pos_infinity || le_cursor->neg_infinity) { |
132 | return; |
133 | } |
134 | DBT *cursor_key = &le_cursor->ft_cursor->key; |
135 | estimate->data = toku_xrealloc(estimate->data, cursor_key->size); |
136 | memcpy(estimate->data, cursor_key->data, cursor_key->size); |
137 | estimate->size = cursor_key->size; |
138 | estimate->flags = DB_DBT_REALLOC; |
139 | } |
140 | |