( ctx context.Context, c *Client, wg *sync.WaitGroup, batchSize int, entityChan <-chan SpannerStruct, toMutationFn func(SpannerStruct) (*spanner.Mutation, error), table string, errChan chan error, workerID int)
| 1677 | ExternalStruct any, |
| 1678 | SpannerStruct any, |
| 1679 | Key comparable](c *Client) *entityWriter[M, ExternalStruct, SpannerStruct, Key] { |
| 1680 | return &entityWriter[M, ExternalStruct, SpannerStruct, Key]{c} |
| 1681 | } |
| 1682 | |
| 1683 | func newEntityReader[ |
| 1684 | M readableEntityMapper[ExternalStruct, SpannerStruct, Key], |
| 1685 | SpannerStruct any, |
| 1686 | ExternalStruct any, |
| 1687 | Key comparable](c *Client) *entityReader[M, ExternalStruct, SpannerStruct, Key] { |
| 1688 | return &entityReader[M, ExternalStruct, SpannerStruct, Key]{c} |
| 1689 | } |
| 1690 | |
| 1691 | func newEntityRemover[ |
| 1692 | M removableEntityMapper[ExternalStruct, SpannerStruct, Key], |
| 1693 | SpannerStruct any, |
| 1694 | ExternalStruct any, |
| 1695 | Key comparable](c *Client) *entityRemover[M, ExternalStruct, SpannerStruct, Key] { |
| 1696 | return &entityRemover[M, ExternalStruct, SpannerStruct, Key]{c} |
| 1697 | } |
| 1698 | |
| 1699 | func concurrentBatchWriteEntity[SpannerStruct any]( |
| 1700 | ctx context.Context, c *Client, wg *sync.WaitGroup, batchSize int, |
| 1701 | entityChan <-chan SpannerStruct, toMutationFn func(SpannerStruct) (*spanner.Mutation, error), |
| 1702 | table string, errChan chan error, workerID int) { |
| 1703 | var totalBatches, entityCount uint |
| 1704 | success := true |
| 1705 | defer func() { |
| 1706 | wg.Done() |
| 1707 | slog.InfoContext(ctx, "batch writer worker finishing", "id", workerID, |
| 1708 | "totalBatches", totalBatches, "entityCount", entityCount, |
| 1709 | "success", success, "table", table) |
| 1710 | }() |
| 1711 | slog.InfoContext(ctx, "batch writer worker starting", "id", workerID, "table", table) |
| 1712 | for { |
| 1713 | batch := make([]*spanner.Mutation, 0, batchSize) |
| 1714 | for range batchSize { |
| 1715 | select { |
| 1716 | case entity, isChannelStillOpen := <-entityChan: |
| 1717 | // If the channel is closed, go ahead and apply what we have and return. |
| 1718 | if !isChannelStillOpen { |
| 1719 | if len(batch) > 0 { |
| 1720 | slog.InfoContext(ctx, "sending final batch", "size", len(batch), "id", workerID, "table", table) |
| 1721 | totalBatches++ |
| 1722 | entityCount += uint(len(batch)) |
| 1723 | err := c.BatchWriteMutations(ctx, c.Client, batch) |
| 1724 | if err != nil { |
| 1725 | success = false |
| 1726 | errChan <- err |
| 1727 | } |
| 1728 | } |
| 1729 | |
| 1730 | return |
| 1731 | } |
| 1732 | // Else, the channel is still open and it has received a value. |
| 1733 | // Create a mutation and append it to the upcoming batch |
| 1734 | m, err := toMutationFn(entity) |
| 1735 | if err != nil { |
| 1736 | success = false |
no test coverage detected