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/*======
5This file is part of PerconaFT.
6
7
8Copyright (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
51struct 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
57int
58toku_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
83void 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
91int
92toku_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
107bool
108toku_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
127void
128toku_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