-
Notifications
You must be signed in to change notification settings - Fork 93
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conduit: filereader / filewriter plugins and compatibility changes. #1253
Merged
Merged
Changes from 30 commits
Commits
Show all changes
39 commits
Select commit
Hold shift + click to select a range
3e9cc08
Write block and state delta to separate files.
winder 189c216
Include certificate in block
winder 33d3dbc
Simplify.
winder 1266432
Revert new config
winder f70cc78
Save genesis file.
winder e59c02a
Allow providing the filename pattern that blocks are written to.
winder 965f562
Make encode/decode utilities.
winder 06d4a6b
Fix typos
winder 4026dc6
Add file reader.
winder 2cb9343
No special case for retry duration of 0.
winder 390da37
Option to drop the certificate before writing.
winder 99f6a73
Fix test.
winder fae7294
Add gzip option to encode/decode.
winder c6ea439
Fix gzip header.
winder 5a613fd
Close the reader.
winder 74b4736
Use the EncodeToFile function in the exporter.
winder 8c7883f
Allow empty delta on round 0
winder 395489a
Add some logging, create localledger dir if needed.
winder e89a207
Add missing error message and some TODOs for useful configs that shou…
winder ca0f4fc
This is much more performant for large blocks.
winder 24d537a
Add some extra timing information.
winder 6922b12
unmarshalConfig change.
winder 6dd292f
Fix import.
winder f318282
Fix self assign.
winder 0fe7bd7
Merge branch 'conduit' into will/filewriter-statedelta
winder 379e949
Merge branch 'conduit' into will/filewriter-statedelta
winder de99a0d
Fix merge error.
winder fdb3191
Fix make integration
winder d0e0ec1
Fix test.
winder f8ccabc
Merge branch 'conduit' into will/filewriter-statedelta
winder 9b584b5
Merge branch 'conduit' into will/filewriter-statedelta
winder c16e353
Merge branch 'conduit' into will/filewriter-statedelta
winder 75e011b
Fix block_processor parameters.
winder 559f542
Fix indexer-data-dir
winder 10fa5ac
Temporary - extra logging.
winder 107b81b
Revert "Temporary - extra logging."
winder 4706d90
More data dir fixes.
winder 77002a6
misc
winder eb6631e
Remove a TODO
winder File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -13,19 +13,23 @@ import ( | |
|
||
"github.com/algorand/go-algorand/crypto" | ||
"github.com/algorand/go-algorand/data/bookkeeping" | ||
|
||
"github.com/algorand/indexer/data" | ||
"github.com/algorand/indexer/exporters" | ||
"github.com/algorand/indexer/plugins" | ||
"github.com/algorand/indexer/util" | ||
) | ||
|
||
const exporterName = "file_writer" | ||
const ( | ||
exporterName = "file_writer" | ||
// FilePattern is used to name the output files. | ||
FilePattern = "%[1]d_block.json" | ||
) | ||
|
||
type fileExporter struct { | ||
round uint64 | ||
blockMetadataFile string | ||
blockMetadata BlockMetaData | ||
cfg ExporterConfig | ||
cfg Config | ||
logger *logrus.Logger | ||
} | ||
|
||
|
@@ -58,11 +62,16 @@ func (exp *fileExporter) Metadata() exporters.ExporterMetadata { | |
|
||
func (exp *fileExporter) Init(_ context.Context, cfg plugins.PluginConfig, logger *logrus.Logger) error { | ||
exp.logger = logger | ||
if err := exp.unmarhshalConfig(string(cfg)); err != nil { | ||
var err error | ||
exp.cfg, err = unmarshalConfig(string(cfg)) | ||
if err != nil { | ||
return fmt.Errorf("connect failure in unmarshalConfig: %w", err) | ||
} | ||
if exp.cfg.FilenamePattern == "" { | ||
exp.cfg.FilenamePattern = FilePattern | ||
} | ||
// create block directory | ||
err := os.Mkdir(exp.cfg.BlocksDir, 0755) | ||
err = os.Mkdir(exp.cfg.BlocksDir, 0755) | ||
if err != nil && errors.Is(err, os.ErrExist) { | ||
} else if err != nil { | ||
return fmt.Errorf("Init() error: %w", err) | ||
|
@@ -113,12 +122,7 @@ func (exp *fileExporter) Config() plugins.PluginConfig { | |
|
||
func (exp *fileExporter) encodeMetadataToFile() error { | ||
tempFilename := fmt.Sprintf("%s.temp", exp.blockMetadataFile) | ||
file, err := os.Create(tempFilename) | ||
if err != nil { | ||
return fmt.Errorf("encodeMetadataToFile(): failed to create temp metadata file: %w", err) | ||
} | ||
defer file.Close() | ||
err = json.NewEncoder(file).Encode(exp.blockMetadata) | ||
err := util.EncodeToFile(tempFilename, exp.blockMetadata, true) | ||
if err != nil { | ||
return fmt.Errorf("encodeMetadataToFile(): failed to write temp metadata: %w", err) | ||
} | ||
|
@@ -143,21 +147,24 @@ func (exp *fileExporter) Receive(exportData data.BlockData) error { | |
if exportData.Round() != exp.round { | ||
return fmt.Errorf("Receive(): wrong block: received round %d, expected round %d", exportData.Round(), exp.round) | ||
} | ||
//write block to file | ||
blockFile := path.Join(exp.cfg.BlocksDir, fmt.Sprintf("block_%d.json", exportData.Round())) | ||
file, err := os.OpenFile(blockFile, os.O_WRONLY|os.O_CREATE, 0755) | ||
if err != nil { | ||
return fmt.Errorf("Receive(): error opening file %s: %w", blockFile, err) | ||
} | ||
defer file.Close() | ||
err = json.NewEncoder(file).Encode(exportData) | ||
if err != nil { | ||
return fmt.Errorf("Receive(): error encoding exportData: %w", err) | ||
|
||
// write block to file | ||
{ | ||
if exp.cfg.DropCertificate { | ||
exportData.Certificate = nil | ||
} | ||
|
||
blockFile := path.Join(exp.cfg.BlocksDir, fmt.Sprintf(exp.cfg.FilenamePattern, exportData.Round())) | ||
err := util.EncodeToFile(blockFile, exportData, true) | ||
if err != nil { | ||
return fmt.Errorf("Receive(): failed to write file %s: %w", blockFile, err) | ||
} | ||
exp.logger.Infof("Wrote block %d to %s", exportData.Round(), blockFile) | ||
} | ||
exp.logger.Infof("Added block %d", exportData.Round()) | ||
|
||
exp.round++ | ||
exp.blockMetadata.NextRound = exp.round | ||
err = exp.encodeMetadataToFile() | ||
err := exp.encodeMetadataToFile() | ||
if err != nil { | ||
return fmt.Errorf("Receive() metadata encoding err %w", err) | ||
} | ||
|
@@ -168,12 +175,17 @@ func (exp *fileExporter) HandleGenesis(genesis bookkeeping.Genesis) error { | |
// check genesis hash | ||
gh := crypto.HashObj(genesis).String() | ||
if exp.blockMetadata.GenesisHash == "" { | ||
// First time initialization. | ||
exp.blockMetadata.GenesisHash = gh | ||
exp.blockMetadata.Network = string(genesis.Network) | ||
err := exp.encodeMetadataToFile() | ||
if err != nil { | ||
if err := exp.encodeMetadataToFile(); err != nil { | ||
return fmt.Errorf("HandleGenesis() metadata encoding err %w", err) | ||
} | ||
|
||
genesisFilename := path.Join(exp.cfg.BlocksDir, "genesis.json") | ||
if err := util.EncodeToFile(genesisFilename, genesis, true); err != nil { | ||
return fmt.Errorf("HandleGenesis() failed to serialize genesis file: %w", err) | ||
} | ||
} else { | ||
if exp.blockMetadata.GenesisHash != gh { | ||
return fmt.Errorf("HandleGenesis() genesis hash in metadata does not match expected value: actual %s, expected %s", gh, exp.blockMetadata.GenesisHash) | ||
|
@@ -186,8 +198,10 @@ func (exp *fileExporter) Round() uint64 { | |
return exp.round | ||
} | ||
|
||
func (exp *fileExporter) unmarhshalConfig(cfg string) error { | ||
return yaml.Unmarshal([]byte(cfg), &exp.cfg) | ||
func unmarshalConfig(cfg string) (Config, error) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Contender for generics right here, we have the same function (with the same typo) in lots of places. I turned it into a pure function in a few places. |
||
var config Config | ||
err := yaml.Unmarshal([]byte(cfg), &config) | ||
return config, err | ||
} | ||
|
||
func init() { | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,21 @@ | ||
package filewriter | ||
|
||
// ExporterConfig specific to the file exporter | ||
type ExporterConfig struct { | ||
// full file path to a directory | ||
// where the block data should be stored. | ||
// Create if directory doesn't exist | ||
// Config specific to the file exporter | ||
type Config struct { | ||
// BlocksDir is the path to a directory where block data should be stored. | ||
// The directory is created if it doesn't exist. | ||
BlocksDir string `yaml:"block-dir"` | ||
// FilenamePattern is the format used to write block files. It uses go | ||
// string formatting and should accept one number for the round. | ||
// If the file has a '.gz' extension, blocks will be gzipped. | ||
// Default: "%[1]d_block.json" | ||
FilenamePattern string `yaml:"filename-pattern"` | ||
// DropCertificate is used to remove the vote certificate from the block data before writing files. | ||
DropCertificate bool `yaml:"drop-certificate"` | ||
|
||
// TODO: compression level - Default, Fastest, Best compression, etc | ||
|
||
// TODO: How to avoid having millions of files in a directory? | ||
// Write batches of blocks to a single file? | ||
// Tree of directories | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
File reader needs the genesis file.