Skip to content

Instantly share code, notes, and snippets.

@emcfarlane
Created November 30, 2021 22:55
Show Gist options
  • Save emcfarlane/965cf56e14ebddf0866f9a19000f0e62 to your computer and use it in GitHub Desktop.
Save emcfarlane/965cf56e14ebddf0866f9a19000f0e62 to your computer and use it in GitHub Desktop.
// counter is a chunked firestore counter.
type counter struct {
id string
sync.Mutex
value big.Int
limit big.Int
}
type Counter struct {
ID string
Value string
}
func (s *Server) newSerialNumber(ctx context.Context, counterID string) (*big.Int, error) {
s.counter.Lock()
defer s.counter.Unlock()
value := new(big.Int).Set(&s.counter.value)
limit := new(big.Int).Set(&s.counter.limit)
if r := value.Cmp(limit); r >= 0 {
s.store.Collection("counters").Doc(counterID)
if err := s.store.RunTransaction(ctx, func(ctx context.Context, tx *firestore.Transaction) error {
snap, err := tx.Get(doc)
if err != nil {
return err
}
var counter Counter
if err := snap.DataTo(&counter); err != nil {
return err
}
if err := value.UnmarshalText([]byte(counter.Value)); err != nil {
return err
}
limit.SetInt64(counterChunkSize).Add(limit, value)
return tx.Set(doc, map[string]interface{}{
"value": limit.String(),
}, firestore.MergeAll)
}); err != nil {
return nil, err
}
}
// update values after transaction
result := big.NewInt(1)
s.counter.value.Set(value.Add(value, result))
s.counter.limit.Set(limit)
return result.Set(&s.counter.value), nil
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment