// NewLedgerClosePump starts a background proc that continually watches the // history database provided. The watch is stopped after the provided context // is cancelled. // // Every second, the proc spawned by calling this func will check to see // if a new ledger has been imported (by ruby-horizon as of 2015-04-30, but // should eventually end up being in this project). If a new ledger is seen // the the channel returned by this function emits func NewLedgerClosePump(ctx context.Context, q *history.Q) <-chan struct{} { result := make(chan struct{}) go func() { var lastSeenLedger int32 for { select { case <-time.After(1 * time.Second): var latestLedger int32 err := q.LatestLedger(&latestLedger) if err != nil { log.Warn("Failed to check latest ledger", err) continue } if latestLedger > lastSeenLedger { log.Debugf("saw new ledger: %d, prev: %d", latestLedger, lastSeenLedger) select { case result <- struct{}{}: lastSeenLedger = latestLedger default: log.Debug("ledger pump channel is blocked. waiting...") } } else if latestLedger < lastSeenLedger { log.Warn("latest ledger went backwards! reseting ledger pump") lastSeenLedger = 0 } case <-ctx.Done(): log.Info("canceling ledger pump") close(result) return } } }() return result }
// Account ingests the provided account data into a new row in the // `history_accounts` table func (ingest *Ingestion) Account(id int64, address string) error { q := history.Q{Repo: ingest.DB} var existing history.Account err := q.AccountByAddress(&existing, address) if err != nil && !q.NoRows(err) { return err } // already imported if !q.NoRows(err) { return nil } sql := ingest.accounts.Values(id, address) _, err = ingest.DB.Exec(sql) if err != nil { return err } return nil }
// ReingestOutdated finds old ledgers and reimports them. func (i *System) ReingestOutdated() (n int, err error) { q := history.Q{Repo: i.HorizonDB} // NOTE: this loop will never terminate if some bug were cause a ledger // reingestion to silently fail. for { outdated := []int32{} err = q.OldestOutdatedLedgers(&outdated, CurrentVersion) if err != nil { return } if len(outdated) == 0 { return } log. WithField("lowest_sequence", outdated[0]). WithField("batch_size", len(outdated)). Info("reingest: outdated") var start, end int32 flush := func() error { ingested, ferr := i.ReingestRange(start, end) if ferr != nil { return ferr } n += ingested return nil } for idx := range outdated { seq := outdated[idx] if start == 0 { start = seq end = seq continue } if seq == end+1 { end = seq continue } err = flush() if err != nil { return } start = seq end = seq } err = flush() if err != nil { return } } }