Skip to content

Commit c21fe14

Browse files
committed
ha_memem
1 parent a6b33af commit c21fe14

File tree

5 files changed

+419
-0
lines changed

5 files changed

+419
-0
lines changed

mysql-test/suite/x/r/ha_memem.result

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
Simple test to verify MEMEM storage engine
2+
create database testdb;
3+
use testdb;
4+
drop table if exists testtbl;
5+
Warnings:
6+
Note 1051 Unknown table 'testdb.testtbl'
7+
drop table if exists testtbl2;
8+
Warnings:
9+
Note 1051 Unknown table 'testdb.testtbl2'
10+
create table testtbl(a int, b int) engine = MEMEM;
11+
insert into testtbl values (2, 1029);
12+
insert into testtbl values (92, 8);
13+
select * from testtbl where a>2;
14+
a b
15+
92 8
16+
create table testtbl2(a int) engine = MEMEM;
17+
insert into testtbl2 values (322);
18+
insert into testtbl2 values (8);
19+
select * from testtbl2 where a > 20;
20+
a
21+
322
22+
drop database testdb;

mysql-test/suite/x/t/ha_memem.test

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
--echo Simple test to verify MEMEM storage engine
2+
3+
create database testdb;
4+
use testdb;
5+
6+
7+
drop table if exists testtbl;
8+
drop table if exists testtbl2;
9+
10+
create table testtbl(a int, b int) engine = MEMEM;
11+
insert into testtbl values (2, 1029);
12+
insert into testtbl values (92, 8);
13+
select * from testtbl where a>2;
14+
15+
create table testtbl2(a int) engine = MEMEM;
16+
insert into testtbl2 values (322);
17+
insert into testtbl2 values (8);
18+
select * from testtbl2 where a > 20;
19+
20+
drop database testdb;

storage/memem/CMakeLists.txt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
SET(MEMEM_PLUGIN_STATIC "memem")
2+
SET(MEMEM_PLUGIN_MANDATORY TRUE)
3+
4+
SET(MEMEM_SOURCES
5+
ha_memem.cc
6+
ha_memem.h
7+
)
8+
9+
MYSQL_ADD_PLUGIN(memem ${MEMEM_SOURCES}
10+
STORAGE_ENGINE MANDATORY
11+
LINK_LIBRARIES extra::rapidjson)

storage/memem/ha_memem.cc

Lines changed: 322 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,322 @@
1+
#include "mysql/plugin.h"
2+
#include "sql/sql_class.h"
3+
#include "storage/memem/ha_memem.h"
4+
5+
//------------------------------------------------------
6+
// Flags
7+
//------------------------------------------------------
8+
9+
/**
10+
* @brief Get the storage engine name
11+
*
12+
* Returns the name used to identify this storage engine.
13+
* This name is used in SHOW TABLE STATUS and SHOW CREATE TABLE.
14+
*
15+
* @return const char* Storage engine name
16+
*/
17+
const char* ha_memem::table_type() const { return "MEMEM"; }
18+
19+
/**
20+
* @brief Get table flags that specify handler capabilities
21+
*
22+
* Returns a bitmap of flags that tells MySQL about the capabilities
23+
* of this storage engine. Current flags:
24+
* - HA_NO_TRANSACTIONS: Engine doesn't support transactions
25+
* - HA_BINLOG_ROW_CAPABLE: Can handle row-based binary logging
26+
*
27+
* @return ulonglong Bitmap of handler flags
28+
*/
29+
ulonglong ha_memem::table_flags() const {
30+
return HA_NO_TRANSACTIONS | HA_BINLOG_ROW_CAPABLE;
31+
}
32+
33+
/**
34+
* @brief Get index capabilities
35+
*
36+
* Returns flags that indicate what kind of indexes this storage engine
37+
* supports. Returns 0 as this basic implementation doesn't support indexes.
38+
*/
39+
uLong ha_memem::index_flags(uint, uint, bool) const { return 0; }
40+
41+
//------------------------------------------------------
42+
// Core
43+
//------------------------------------------------------
44+
45+
//
46+
// Called when: CREATE TABLE is executed
47+
// Purpose: Initialize the table structure/files
48+
//
49+
int ha_memem::create(const char* name,
50+
TABLE* form [[maybe_unused]],
51+
HA_CREATE_INFO* create_info [[maybe_unused]],
52+
dd::Table* table_def [[maybe_unused]]) {
53+
mem_table = new MememTable();
54+
mem_table->name = name;
55+
thr_lock_init(&mem_table->lock); // Initialize lock
56+
thr_lock_data_init(&mem_table->lock, &lock, NULL); // Initialize lock data
57+
return 0;
58+
}
59+
60+
//
61+
// Called when: Table is opened for operations
62+
// Purpose: Open existing table for read/write
63+
//
64+
int ha_memem::open(const char* name,
65+
int mode [[maybe_unused]],
66+
uint test_if_locked [[maybe_unused]],
67+
const dd::Table* table_def [[maybe_unused]]) {
68+
mem_table = new MememTable();
69+
mem_table->name = name;
70+
thr_lock_init(&mem_table->lock); // Initialize lock
71+
thr_lock_data_init(&mem_table->lock, &lock, NULL); // Initialize lock data
72+
return 0;
73+
}
74+
75+
int ha_memem::close() {
76+
if (mem_table) {
77+
thr_lock_delete(&mem_table->lock); // Clean up lock
78+
delete mem_table;
79+
mem_table = nullptr;
80+
}
81+
return 0;
82+
}
83+
84+
85+
int ha_memem::write_row(uchar* buf) {
86+
size_t row_length = table->s->stored_rec_length;
87+
mem_table->rows.emplace_back(buf, buf + row_length);
88+
return 0;
89+
}
90+
91+
/**
92+
* @brief Initialize table scanning
93+
*
94+
* Called before starting a table scan. Initializes position
95+
* for sequential reading of rows.
96+
*
97+
* @param scan True if this is a full table scan
98+
* @return int 0 for success, non-zero for failure
99+
*/
100+
int ha_memem::rnd_init(bool scan [[maybe_unused]]) {
101+
current_position = 0;
102+
return 0;
103+
}
104+
105+
/**
106+
* @brief Read the next row in a table scan
107+
*
108+
* Reads the next row in a sequential scan and places it in
109+
* the provided buffer.
110+
*
111+
* @param buf Buffer to store the row
112+
* @return int 0 for success, HA_ERR_END_OF_FILE for end of table
113+
*/
114+
int ha_memem::rnd_next(uchar* buf) {
115+
if (current_position >= mem_table->rows.size()) {
116+
return HA_ERR_END_OF_FILE;
117+
}
118+
119+
memcpy(buf, mem_table->rows[current_position].data(),
120+
mem_table->rows[current_position].size());
121+
current_position++;
122+
return 0;
123+
}
124+
125+
/**
126+
* @brief Store position for later retrieval
127+
*
128+
* Stores current position for later retrieval by rnd_pos().
129+
* Used for ORDER BY and GROUP BY operations.
130+
*
131+
* @param record Currently unused
132+
*/
133+
void ha_memem::position(const uchar*) {
134+
size_t* position = reinterpret_cast<size_t*>(ref);
135+
*position = current_position - 1;
136+
}
137+
138+
/**
139+
* @brief Read a row using position
140+
*
141+
* Reads a row from a given position. The position information
142+
* comes from an earlier call to position().
143+
*
144+
* @param buf Buffer to store the row
145+
* @param pos Position information
146+
* @return int 0 for success, HA_ERR_END_OF_FILE for invalid position
147+
*/
148+
int ha_memem::rnd_pos(uchar* buf, uchar* pos) {
149+
size_t position = *reinterpret_cast<size_t*>(pos);
150+
if (position >= mem_table->rows.size()) {
151+
return HA_ERR_END_OF_FILE;
152+
}
153+
154+
memcpy(buf, mem_table->rows[position].data(),
155+
mem_table->rows[position].size());
156+
return 0;
157+
}
158+
159+
160+
/**
161+
* @brief Information about the table
162+
*
163+
* Called to get information about the table. Currently a no-op
164+
* in this basic implementation.
165+
*
166+
* @param flag Type of information requested
167+
* @return int 0 for success
168+
*/
169+
int ha_memem::info(uint) { return 0; }
170+
171+
//------------------------------------------------------
172+
// Locks
173+
//------------------------------------------------------
174+
175+
/**
176+
* @brief External table lock handler
177+
*
178+
* This function is called by MySQL at the beginning and end of every statement that
179+
* references this table. It manages external/file-level locks for the table.
180+
*
181+
* Called twice for each statement:
182+
* 1. At start with lock_type = F_RDLCK (read) or F_WRLCK (write)
183+
* 2. At end with lock_type = F_UNLCK
184+
*
185+
* For transactional tables, this should be a no-op as transactions
186+
* handle the locking automatically.
187+
*
188+
* @param thd Thread handler (unused in basic implementation)
189+
* @param lock_type Type of lock (F_RDLCK, F_WRLCK, F_UNLCK)
190+
* @return 0 for success, non-zero for failure
191+
*/
192+
int ha_memem::external_lock(THD* thd [[maybe_unused]], int lock_type [[maybe_unused]]) {
193+
DBUG_TRACE;
194+
return 0;
195+
}
196+
197+
/**
198+
* @brief Store lock request in lock structure
199+
*
200+
* This method is called by MySQL to build a list of table-level locks needed
201+
* for a particular statement. It's called multiple times to build the complete
202+
* lock list before actually trying to acquire the locks.
203+
*
204+
* Lock upgrade protocol:
205+
* - If lock_type is TL_IGNORE, keep existing lock type
206+
* - If current lock is TL_UNLOCK, set to requested lock_type
207+
* - Otherwise, keep existing lock type (don't downgrade)
208+
*
209+
* Common lock types:
210+
* - TL_READ: Normal read lock
211+
* - TL_READ_WITH_SHARED_LOCKS: READ with LOCK IN SHARE MODE
212+
* - TL_WRITE: Normal write lock
213+
* - TL_WRITE_ALLOW_WRITE: INSERT operations
214+
*
215+
* @param thd Thread handler
216+
* @param to Pointer to an array of lock requests
217+
* @param lock_type Type of lock requested
218+
* @return Position after the current lock in the lock array
219+
*/
220+
THR_LOCK_DATA** ha_memem::store_lock(THD* thd [[maybe_unused]],
221+
THR_LOCK_DATA** to,
222+
enum thr_lock_type lock_type) {
223+
// Only change lock type if:
224+
// 1. Lock type is not TL_IGNORE
225+
// 2. Current lock type is TL_UNLOCK (no lock)
226+
if (lock_type != TL_IGNORE && lock.type == TL_UNLOCK) {
227+
lock.type = lock_type;
228+
}
229+
230+
// Add this lock to the table's lock list
231+
*to++ = &lock;
232+
233+
// Return position after our lock
234+
return to;
235+
}
236+
237+
//--------------------------------------------------
238+
// Plugin-specific declarations and definitions
239+
//--------------------------------------------------
240+
241+
/**
242+
* @brief Create handler instance for the storage engine
243+
*
244+
* Called by MySQL to create a new handler instance when a table is opened.
245+
* Uses placement new to create the handler in the provided memory root.
246+
*
247+
* @param hton Handlerton for this storage engine
248+
* @param table TABLE_SHARE containing table definition
249+
* @param partitioned Whether table is partitioned (unused in basic implementation)
250+
* @param mem_root Memory root to allocate handler from
251+
* @return handler* Pointer to newly created handler instance
252+
*/
253+
static handler* memem_create_handler(handlerton* hton,
254+
TABLE_SHARE* table,
255+
bool,
256+
MEM_ROOT* mem_root) {
257+
return new (mem_root) ha_memem(hton, table);
258+
}
259+
260+
ha_memem::ha_memem(handlerton* hton, TABLE_SHARE* table_arg)
261+
: handler(hton, table_arg), mem_table(nullptr), current_position(0) {}
262+
263+
ha_memem::~ha_memem() = default;
264+
265+
/** Global handlerton instance for the MEMEM storage engine */
266+
handlerton *memem_hton;
267+
268+
/**
269+
* @brief Initialize the storage engine plugin
270+
*
271+
* Called when the storage engine is loaded. Initializes the handlerton
272+
* with the necessary function pointers and capabilities.
273+
*/
274+
static int memem_init_func(void* p) {
275+
memem_hton = (handlerton *)p;
276+
memem_hton->state = SHOW_OPTION_YES; // Mark plugin as active
277+
memem_hton->create = memem_create_handler; // Set handler creation function
278+
memem_hton->flags = HTON_CAN_RECREATE; // Set capabilities
279+
return 0;
280+
}
281+
282+
static int memem_deinit_func(void* p [[maybe_unused]]) {
283+
return 0;
284+
}
285+
286+
/**
287+
* @brief Storage engine descriptor
288+
*
289+
* Contains version information for the storage engine interface.
290+
* Used by MySQL to verify compatibility.
291+
*/
292+
static struct st_mysql_storage_engine memem_storage_engine = {
293+
MYSQL_HANDLERTON_INTERFACE_VERSION
294+
};
295+
296+
/**
297+
* @brief Plugin declaration structure
298+
*
299+
* Declares the storage engine plugin to MySQL, including:
300+
* - Plugin type (storage engine)
301+
* - Name and author information
302+
* - License information
303+
* - Initialize and cleanup functions
304+
* - Version and status information
305+
*/
306+
mysql_declare_plugin(memem) {
307+
MYSQL_STORAGE_ENGINE_PLUGIN,
308+
&memem_storage_engine, // Plugin descriptor
309+
"MEMEM", // Plugin name
310+
PLUGIN_AUTHOR_ORACLE, // Author
311+
"MEMEM storage engine", // Description
312+
PLUGIN_LICENSE_GPL, // License
313+
memem_init_func, // Initialization function
314+
nullptr, // Check uninstall function
315+
memem_deinit_func, // Cleanup function
316+
0x0001, // Version number (0.1)
317+
nullptr, // Status variables
318+
nullptr, // System variables
319+
nullptr, // Config options
320+
0, // Flags
321+
}
322+
mysql_declare_plugin_end;

0 commit comments

Comments
 (0)