Gli sviluppatori di OrioleDB hanno analizzato lo stato attuale dell'API a basso livello utilizzata per l'accesso alle estensioni per tabelle e indici in PostgreSQL (metodo di accesso a tabelle/indici - API) e hanno proposto modi per migliorarlo. Da quando è stato introdotto in PostgreSQL 12, questo API ha permesso agli sviluppatori di creare meccanismi alternativi di storage. Tuttavia, nonostante la presenza di questo API e le note limitazioni del meccanismo di storage integrato, non sono ancora emersi motori di storage transazionali completamente funzionanti realizzati esclusivamente come estensioni.
Le funzionalità più richieste per i motori di tabella alternativi in PostgreSQL sono:
- Implementazioni MVCC alternative, ad esempio, storage basati su log UNDO.
- Tabelle organizzate per indice, dove l'indice non è un complemento facoltativo della tabella che accelera le query, ma rappresenta la struttura principale in cui sono memorizzati i dati della tabella.
Le modifiche necessarie all'API Table/Index AM per supportare implementazioni MVCC alternative vengono esaminate tenendo in considerazione l'estensione OrioleDB, progettata per affrontare le note vulnerabilità del meccanismo di storage integrato di PostgreSQL. Il problema è che per una piena integrazione di OrioleDB con PostgreSQL sono necessarie modifiche al codice di PostgreSQL, il che complica l'implementazione del progetto e sottolinea la necessità di modernizzare l'attuale API Table AM.
API Table AM non impone direttamente come realizzare il MVCC. Tuttavia, l'API Table AM e l'API Index AM fanno la seguente assunzione: ogni TID (Tuple/row Identifier) è indicizzato da tutti gli indici o non è indicizzato affatto. Anche se l'Index AM ha più riferimenti a un TID (ad esempio, GIN), tutti questi riferimenti devono corrispondere allo stesso valore indicizzato.

Questo principio è stato criticato per l'aumento delle operazioni di scrittura («scrittura amplificata») - se viene aggiornato un attributo indicizzato, è necessario aggiornare ogni indice nella tabella. Per sfruttare appieno i vantaggi del log UNDO o costruire un altro metodo di storage senza «amplificazione della scrittura» (ad esempio, il metodo WARM), è necessario violare questa assunzione.

Un Table AM basato su UNDO, che non violerà questa assunzione, è simile all'esistente metodo HOT (Heap-Only Tuples), tranne per il fatto che le vecchie versioni delle righe vengono mantenute nel log UNDO e non devono adattarsi nella stessa pagina. Tuttavia, secondo gli autori, questo vantaggio non è sufficiente a giustificare l'esistenza di un Table AM separato.
Restrizioni pratiche dell'attuale API:
- Durante l'aggiornamento di una riga della tabella, gli indici vengono aggiornati secondo il principio «tutto o niente».
- Mancanza di capacità nell'API Index AM per l'eliminazione mirata di specifici tuple. Attualmente è possibile eliminare tuple dagli indici in modo massivo usando i metodi ambulkdelete e amvacuumcleanup. Tentare di implementare l'eliminazione mirata attraverso questo API porterebbe a un'elevata inefficienza, poiché la maggior parte delle implementazioni attuali deve scansionare l'intero indice. Inoltre, l'API non consente di specificare quali tuple, che fanno riferimento allo stesso TID, dovrebbero essere eliminate. Può solo eliminarle tutte.
- Gli indici attualmente fanno riferimento alle righe della tabella tramite il numero del blocco (32 bit) e il numero di offset (16 bit). Solo 11 bit dell'offset possono essere trasferiti in modo sicuro dal TID della tabella a tutti i metodi di accesso all'indice. Pertanto, implementazioni alternative di MVCC potrebbero necessitare di memorizzare un carico utile aggiuntivo (payload) insieme al TID. Ad esempio, in OrioleDB è necessario un o più bit per implementare indici di «segnalazione di eliminazione» o informazioni complete sulla visibilità.
Sono stati proposti due modi per superare le restrizioni nella pratica:
Approccio 1: L'API Index AM fornisce possibilità per un'implementazione alternativa di MVCC.
Mentre il Table AM continua a gestire tutti i componenti MVCC, l'Index AM fornisce le necessarie capacità per un'implementazione alternativa di MVCC, ovvero: memorizzazione di carico utile (payload) personalizzato insieme al TID, metodo di eliminazione mirata e persino metodo di aggiornamento mirato (se il TID nell'indice non può essere modificato, il carico utile personalizzato può). Inoltre, poiché è necessario consentire a più tuple dell'indice di riferirsi allo stesso TID, anche i metodi API utilizzati durante la scansione dell'indice necessitano di aggiornamenti.
Approccio 2: Indici che supportano MVCC.
Un'alternativa sarebbe consentire indici che supportano MVCC. Cioè, l'«executor» (o forse il Table AM) chiama semplicemente i metodi insert() e delete() nel Index AM, mentre il Index AM fornisce la possibilità di scansione tenendo conto di MVCC. Questo semplificherebbe notevolmente la scansione utilizzando solo gli indici (index-only). Anche l'intero Table AM in tal caso potrebbe diventare uno strato intermedio che memorizza i dati nell'indice.
Nel diagramma qui sotto è fornito un esempio. Il valore dell'indice 2 è aggiornato dalla transazione 11 da «A» a «B». Pertanto, il valore «A» è contrassegnato come xmax == 11, mentre il valore «B» è contrassegnato come xmin == 11. In questo modo si può scansionare l'indice 2 e ottenere solo le tuple visibili in conformità con MVCC senza controlli sull'heap. La raccolta dei rifiuti dell'indice 2 può anche essere eseguita senza utilizzare l'heap.

Con l'implementazione di tutte le innovazioni elencate nell'API dei metodi di accesso agli indici, è improbabile che si riesca a modificare contemporaneamente tutti gli indici per supportare tutte le nuove funzionalità. È più realistico consentire diverse implementazioni per un singolo metodo di accesso all'indice. Ad esempio, oltre al consueto B-tree, l'estensione potrebbe implementare un B-tree alternativo con supporto per MVCC all'interno dell'indice e supporto per identificatori di registro di lunghezza variabile.

Pertanto, si propone di rivedere non solo l'API del Table AM, ma anche l'API del Index AM, che ha servito la comunità PostgreSQL per molti anni. Inoltre, si propone di separare il Index AM in uno strato logico e uno strato di implementazione. Questa architettura riconsiderata permetterà a PostgreSQL di supportare diverse modelli di archiviazione.
Fonte: opennet.ru
