Ich brauche einen Hinweis auf die Datenstruktur als atomare Änderungsprotokoll verwenden.STM-freundliche Liste als Änderungsprotokoll
Ich versuche, den folgenden Algorithmus zu implementieren. Es gibt einen Fluss von eingehenden Änderungen, die eine In-Memory-Map aktualisieren. In Haskell-ähnlichen Pseudo-Code ist es
update :: DataSet -> SomeListOf Change -> Change -> STM (DataSet, SomeListOf Change)
update dataSet existingChanges newChange = do
...
return (dataSet, existingChanges ++ [newChange])
wo DataSet Karte ist (derzeit ist es die Karte aus dem stm-Container-Paket, https://hackage.haskell.org/package/stm-containers-0.2.10/docs/STMContainers-Map.html). Das ganze "Update" wird aus einer beliebigen Anzahl von Threads aufgerufen. Einige der Änderungen können aufgrund der Domänensemantik zurückgewiesen werden. Dafür verwende ich throwSTM, um den Effekt der Transaktion wegzuwerfen. Bei erfolgreichem Commit wird "newChange" zur Liste hinzugefügt.
Es gibt getrennte Threads, die folgende Funktion aufruft:
flush :: STM (DataSet, SomeListOf Change) -> IO()
diese Funktion soll die aktuelle Momentaufnahme der DataSet nehmen zusammen mit der Liste der Änderungen (es muss ein einheitliches Paar) und spülen Sie es an das Dateisystem, dh
Ich brauche einen Hinweis über die Datenstruktur für "SomeListOf Change" zu verwenden. Ich möchte [Change] nicht verwenden, weil es "zu geordnet" ist und ich befürchte, dass es zu viele Konflikte geben wird, die die gesamte Transaktion erneut versuchen werden. Bitte korrigiere mich, wenn ich hier falsch liege.
Ich kann das Set (https://hackage.haskell.org/package/stm-containers-0.2.10/docs/STMContainers-Set.html) nicht verwenden, weil ich noch einige Ordnung, z. Die Reihenfolge der Transaktion wird bestätigt. Ich könnte TChan dafür verwenden, und es sieht wie eine gute Übereinstimmung aus (genau die Reihenfolge der Transaktion commits), aber ich weiß nicht, wie man die "flush" Funktion implementiert, so dass es die konsistente Ansicht des gesamten Änderungsprotokolls zusammen geben würde mit dem DataSet.
Die aktuelle Implementierung davon ist hier https://github.com/lolepezy/rpki-pub-server/blob/add-storage/src/RRDP/Repo.hs, in den Funktionen applyActionsToState bzw. rrdpSyncThread. Es benutzt TChan und scheint es falsch zu machen.
Vielen Dank im Voraus.
Update: Eine vernünftige Antwort scheint wie die
type SomeListOf c = TChan [c]
update :: DataSet -> TChan [Change] -> Change -> STM DataSet
update dataSet existingChanges newChange = do
...
writeTChan changeChan $ reverse (newChange : existingChanges)
return dataSet
flush data_ = do
(dataSet, changes) <- atomically $ (,) <$> readTVar data_ <*> readTChan changeChan
-- write them both to FS
-- ...
Aber ich bin immer noch nicht sicher zu sein, ob es sich um eine saubere Lösung ist die gesamte Liste als Element des Kanals zu übergeben.
Ich habe Ihre Frage nicht sorgfältig gelesen, aber 'TChan' ist eine dead-simple' ([a], [a]) 'Funktionswarteschlange; es klingt, als könnte es für Sie sinnvoll sein, Ihre eigene Variation zu implementieren. – jberryman
Lass mich fragen: Wie viele Threads (zumindest eine ungefähre Anzahl) werden voraussichtlich auf die Struktur zugreifen? Und wie viele von ihnen auf einmal? Wie groß darf die Liste der Änderungen sein? –
Müssen Sie 'update' auch mit anderen' STM' Operationen erstellen, oder läuft es immer in einer eigenen Transaktion? –