Table Discovery
In MariaDB non è sempre necessario eseguire esplicitamente una CREATE TABLE
perché una tabella compaia. A volte la tabella può già esistere nello Storage Engine, senza che il server lo sappia, perché non c'è un file .frm
associato ad essa. Può accadere per diversi motivi, per esempio perché un motore di cluster ha creato la tabella in un altro server MariaDB. Ma qualunque sia la ragione, vi è un meccanismo con il quale lo Storage Engine può comunicare al server che quella tabella esiste. Il meccanismo si chiama table discovery e gli Storage Engine che vogliono servirsene devono utilizzare la discovery API.
Questa pagina descrive la vecchia discovery API, implementata in MySQL per NDB Cluster. Una nuova API più generica è attualmente in lavorazione.
Si compone di tre parti.
Primo, capisce che una tabella (magari menzionata in una query SELECT
) non esiste, chiede a tutti gli Storage Engine se la conoscono. Per farlo chiama il metodo discover() di handlerton. Il metodo ha la seguente definizione:
int discover(handlerton *hton, THD* thd, const char *db, const char *name, unsigned char **frmblob, size_t *frmlen);
Prende come argomenti il nome del database e della tabella; restituisce 0 se questa esiste, altrimenti 1. Se restituisce 0, ci si aspetta che allochi (con my_malloc()
) un buffer e vi copi l'immagine binaria completa del file .frm
della tabella. Il server lo scrive poi su disco, creando il file .frm
. I parametri di output frmblob
e frmlen
servono a restituire informazioni sul buffer. Spetta al chiamante la responsabilità di deallocare il buffer con my_free()
.
Secondo, in certi casi il server vuole solo sapere se la tabella esiste, ma non ha realmente bisogno di aprirla e non ha bisogno dell'immagine del file .frm
. In questi casi usare il metodo discover()
sarebbe uno spreco di risorse, perciò si usa il più leggero table_exists_in_engine(). Questo metodo ha la seguente definizione:
int table_exists_in_engine(handlerton *hton, THD* thd, const char *db, const char *name);
e restituisce uno dei codici HA_ERR_
, solitamente HA_ERR_NO_SUCH_TABLE
o
HA_ERR_TABLE_EXIST
.
Third, there can be a situation when the server thinks that the table exists (it found and successfully read the .frm
file), but from the engine point of view the .frm
file is incorrect. For example, the table was already deleted from the engine, or its definition was modified (again, modified only in the engine). In this case the .frm
file is outdated, and the server needs to re-discover the table. The engine conveys this to the server by returning HA_ERR_TABLE_DEF_CHANGED
error code from the handler's open() method. On receiving this error the server will use the discover()
method to get the new .frm
image. This also means that after the table is opened, the server does not expect its metadata to change. The engine thus should ensure (with some kind of locking, perhaps) that a table metadata cannot be modified, as long as the table stays opened.
And fourth, a user might want to retrieve a list of tables in a specific database. With SHOW TABLES
or by quering INFORMATION_SCHEMA
tables. The user expects to see all tables, but the server cannot discover them one by one, because it doesnt know table names. In this case, the server uses a special discovery technique. It is find_files() method in the handlerton, defines as
int find_files(handlerton *hton, THD *thd, const char *db, const char *path, const char *wild, bool dir, List<LEX_STRING> *files);
and it, typically for Storage Engine API, returns 0 on success and 1 on failure. The arguments mean db
- the name of the database, path
- the path to it, wild
an SQL wildcard pattern (for example, from SHOW TABLES LIKE '...'
, and dir
, if set, means to discover databases instead of tables.