Implementazione standalone WAL (Write Ahead Log)

0

Sto esplorando come potrei creare un registro di scrittura in anticipo. Il mio caso d'uso è per operazioni come:

  • Registra messaggi (INFO, DEBUG, ecc.)
  • Upload di file

Dove scriverei le informazioni che rappresentano il messaggio di registro o un caricamento di file nel WAL, quindi tentare di svuotare il messaggio nella sua destinazione finale. In effetti quello che sono dopo è una coda persistente. Ho pensato che un WAL si adattava qui e dovrebbe essere facilmente implementato senza dipendenze aggiuntive, forse ho torto, quindi il feedback è apprezzato, poiché la mia applicazione dovrebbe essere in grado di continuare / ripristinare in caso di interruzione di corrente o qualche altro crash.

Il mio dispositivo in questo caso è un chiosco, quindi sarà praticamente solo al mondo da solo a canticchiare finché non accadrà qualcosa di brutto: qualcuno lo scollegherà accidentalmente per esempio e alla fine verrà riacceso. Ho capito che il WAL si adatta allo scenario per il ripristino all'avvio dell'applicazione.

A tal fine, considero System.IO.MemoryMappedFiles.MemoryMappedFile come una potenziale soluzione di implementazione.

Quello che ho abbozzato finora è l'esecuzione di maniglie da 2 mmap.

  1. il WAL
  2. un indice sul WAL

L'intestazione dell'indice memorizzerebbe l'HEAD corrente e il COMMIT corrente. Sto usando COMMIT qui per significare "sì, tutto fino a questo punto è stato gestito con successo"

Ogni punto indice dopo HEAD e COMMIT memorizzerebbero la posizione dei dati WAL nel file WAL.

quindi l'indice sarebbe simile a qualcosa (ogni voce indice rappresenta un int per 4 byte):

Head        Commit      Index 0     Index 1
v           v           v           v
00 00 00 02 00 00 00 01 00 00 00 00 00 00 00 58

La voce di registro 0 inizia dal byte 0 nel file WAL

La voce di registro 1 inizia dal byte 88 nel file WAL

Quindi leggere una voce dal WAL sarebbe una questione di leggere l'indice N per ottenere l'inizio dell'intervallo e quindi leggere l'indice N + 1 per ottenere la fine (ovvero il prossimo avvio).

Dietro le quinte avrei un intervallo di tempo per eseguire i checkpoint e pulire l'indice e il WAL. Sto andando avanti con me stesso in quanto il mio scopo principale con questa domanda è di ottenere un feedback sul tempo o no, questa è anche una buona idea e in tal caso, se si utilizza un MemoryMappedFile per il WAL e l'indice WAL è il modo migliore per gestirlo.

In un caso come catturare i messaggi di log, potrebbe esserci un po 'di scrittura in breve tempo.

    
posta Adam Venturella 21.05.2017 - 15:52
fonte

1 risposta

0

"Migliore" dipende in larga misura dagli scenari di utilizzo e dai criteri per la nozione di "migliore".

Se si sta scrivendo un log che viene letto solo durante il riavvio / ripristino, penso che le ordinarie scritture bufferizzate in un file di sola aggiunta siano le migliori.

Per scrivere un'app accoda solo che è esso stesso il database, e quindi potrebbe essere letto frequentemente più vecchi record di aggiornamento, il concetto mappato in memoria potrebbe essere migliore.

Oltre a ciò ci sono altre cose da dire:

Sull'architettura dei record di aggiornamento nel registro: probabilmente integrarei il contenuto degli aggiornamenti con le informazioni dell'indice, se sono elaborati solo in serie come nel ripristino. Aggiorna i record con un'intestazione che fa riferimento al record di aggiornamento precedente, al contenuto e quindi a un trailer con hash o checksum di qualche tipo per la successiva convalida dell'aggiornamento, insieme a un riferimento all'inizio del record di aggiornamento. D'altra parte, se un consumatore usa letture casuali di aggiornamenti, allora un indice potrebbe aiutare.

Credo che, in generale, un solo utilizzo dei file di append sia più amichevole con un SSD che l'aggiornamento dei primi byte del file insieme a ciascuna append, poiché ciò comporterebbe un minor numero di scritture discontinue.

Se si utilizzano file mappati in memoria, se si aggiunge un file mappato in memoria, sarà necessario mappare in memoria utilizzando una dimensione maggiore del file attualmente: questo per contenere le cose aggiunte. Quando raggiungi la fine della dimensione di mappatura, devi rimappare il file (più grande), poiché Windows non consente di estendere la mappatura man mano che procedi. Quindi, quello che faccio è mappare il file con una grande quantità di gioco, e poi troncare il file alla lunghezza corretta. Certo, sono ancora pronto a rimappare il file se esaurisco il gioco.

Windows esegue il mapping dei file nelle pagine e non traccia l'effettivo EOF (l'atto di mappare il file con allentamento modifica l'EOF del file), pertanto il mantenimento dell'EOF è responsabilità dell'applicazione: è possibile correggere l'EOF in seguito alla chiusura forzata dell'applicazione rimuovendo il file. Tuttavia, se l'app o il sistema si arresta in modo anomalo (ad esempio, potenza persa), il file avrà probabilmente pagine aggiuntive ben oltre l'EOF previsto. Quindi quello che faccio è cercare l'ultimo record di aggiornamento alla ricerca a ritroso dal file EOF (qui è dove l'hash aiuta con la convalida).

    
risposta data 21.05.2017 - 21:48
fonte

Leggi altre domande sui tag