-
Luca Moser authored
* migrates to hive.go database package * review fixes * alias types and vars from hive.go's db package * Move database to tempdir to prevent sideeffects in tests * fix import Co-authored-by:
Wolfgang Welz <welzwo@gmail.com>
Luca Moser authored* migrates to hive.go database package * review fixes * alias types and vars from hive.go's db package * Move database to tempdir to prevent sideeffects in tests * fix import Co-authored-by:
Wolfgang Welz <welzwo@gmail.com>
transaction_metadata.go 4.44 KiB
package tangle
import (
"fmt"
"github.com/iotaledger/goshimmer/packages/database"
"github.com/iotaledger/goshimmer/packages/model/transactionmetadata"
"github.com/iotaledger/hive.go/lru_cache"
"github.com/iotaledger/hive.go/typeutils"
"github.com/iotaledger/iota.go/trinary"
)
// region public api ///////////////////////////////////////////////////////////////////////////////////////////////////
func GetTransactionMetadata(transactionHash trinary.Trytes, computeIfAbsent ...func(trinary.Trytes) *transactionmetadata.TransactionMetadata) (result *transactionmetadata.TransactionMetadata, err error) {
if cacheResult := transactionMetadataCache.ComputeIfAbsent(transactionHash, func() interface{} {
if transactionMetadata, dbErr := getTransactionMetadataFromDatabase(transactionHash); dbErr != nil {
err = dbErr
return nil
} else if transactionMetadata != nil {
return transactionMetadata
} else {
if len(computeIfAbsent) >= 1 {
return computeIfAbsent[0](transactionHash)
}
return nil
}
}); !typeutils.IsInterfaceNil(cacheResult) {
result = cacheResult.(*transactionmetadata.TransactionMetadata)
}
return
}
func ContainsTransactionMetadata(transactionHash trinary.Trytes) (result bool, err error) {
if transactionMetadataCache.Contains(transactionHash) {
result = true
} else {
result, err = databaseContainsTransactionMetadata(transactionHash)
}
return
}
func StoreTransactionMetadata(transactionMetadata *transactionmetadata.TransactionMetadata) {
transactionMetadataCache.Set(transactionMetadata.GetHash(), transactionMetadata)
}
// endregion ///////////////////////////////////////////////////////////////////////////////////////////////////////////
// region lru cache ////////////////////////////////////////////////////////////////////////////////////////////////////
var transactionMetadataCache = lru_cache.NewLRUCache(TRANSACTION_METADATA_CACHE_SIZE, &lru_cache.LRUCacheOptions{
EvictionCallback: onEvictTransactionMetadatas,
EvictionBatchSize: 200,
})
func onEvictTransactionMetadatas(_ interface{}, values interface{}) {
// TODO: replace with apply
for _, obj := range values.([]interface{}) {
if txMetadata := obj.(*transactionmetadata.TransactionMetadata); txMetadata.GetModified() {
if err := storeTransactionMetadataInDatabase(txMetadata); err != nil {
panic(err)
}
}
}
}
func FlushTransactionMetadata() {
transactionCache.DeleteAll()
}
const (
TRANSACTION_METADATA_CACHE_SIZE = 500
)
// endregion ///////////////////////////////////////////////////////////////////////////////////////////////////////////
// region database /////////////////////////////////////////////////////////////////////////////////////////////////////
var transactionMetadataDatabase database.Database
func configureTransactionMetaDataDatabase() {
if db, err := database.Get(database.DBPrefixTransactionMetadata, database.GetBadgerInstance()); err != nil {
panic(err)
} else {
transactionMetadataDatabase = db
}
}
func storeTransactionMetadataInDatabase(metadata *transactionmetadata.TransactionMetadata) error {
if metadata.GetModified() {
if marshaledMetadata, err := metadata.Marshal(); err != nil {
return err
} else {
if err := transactionMetadataDatabase.Set(database.Entry{Key: typeutils.StringToBytes(metadata.GetHash()), Value: marshaledMetadata}); err != nil {
return fmt.Errorf("%w: failed to store transaction metadata: %s", ErrDatabaseError, err)
}
metadata.SetModified(false)
}
}
return nil
}
func getTransactionMetadataFromDatabase(transactionHash trinary.Trytes) (*transactionmetadata.TransactionMetadata, error) {
txMetadata, err := transactionMetadataDatabase.Get(typeutils.StringToBytes(transactionHash))
if err != nil {
if err == database.ErrKeyNotFound {
return nil, nil
}
return nil, fmt.Errorf("%w: failed to retrieve transaction: %s", ErrDatabaseError, err)
}
var result transactionmetadata.TransactionMetadata
if err := result.Unmarshal(txMetadata.Value); err != nil {
panic(err)
}
return &result, nil
}
func databaseContainsTransactionMetadata(transactionHash trinary.Trytes) (bool, error) {
if contains, err := transactionMetadataDatabase.Contains(typeutils.StringToBytes(transactionHash)); err != nil {
return contains, fmt.Errorf("%w: failed to check if the transaction metadata exists: %s", ErrDatabaseError, err)
} else {
return contains, nil
}
}
// endregion ///////////////////////////////////////////////////////////////////////////////////////////////////////////