fix(go): singleflight tdengine child table ensures

This commit is contained in:
lingniu
2026-07-03 19:49:04 +08:00
parent 3a0d9bd840
commit 68b729fa7b
3 changed files with 151 additions and 42 deletions

View File

@@ -40,8 +40,45 @@ type payloadChunk struct {
}
type tableCache struct {
mu sync.Mutex
seen map[string]struct{}
mu sync.Mutex
seen map[string]struct{}
inflight map[string]*tableEnsure
}
type tableEnsure struct {
done chan struct{}
err error
}
func (c *tableCache) doOnce(key string, fn func() error) error {
c.mu.Lock()
if _, ok := c.seen[key]; ok {
c.mu.Unlock()
return nil
}
if c.inflight == nil {
c.inflight = map[string]*tableEnsure{}
}
if entry, ok := c.inflight[key]; ok {
c.mu.Unlock()
<-entry.done
return entry.err
}
entry := &tableEnsure{done: make(chan struct{})}
c.inflight[key] = entry
c.mu.Unlock()
err := fn()
c.mu.Lock()
if err == nil {
c.seen[key] = struct{}{}
}
entry.err = err
delete(c.inflight, key)
close(entry.done)
c.mu.Unlock()
return err
}
func NewWriter(exec Execer) *Writer {
@@ -230,53 +267,39 @@ VALUES %s`, w.qualify(table), strings.Join(rows, ","))); err != nil {
func (w *Writer) ensureRawChild(ctx context.Context, table string, stable string, env envelope.FrameEnvelope) error {
key := stable + "." + table
w.cache.mu.Lock()
_, ok := w.cache.seen[key]
w.cache.mu.Unlock()
if ok {
return nil
}
statement := fmt.Sprintf("CREATE TABLE IF NOT EXISTS %s USING %s TAGS ('%s', '%s', '%s', '%s', '%s')",
w.qualify(table), w.qualify(stable),
quote(string(env.Protocol)),
quote(env.VehicleKey()),
quote(env.VIN),
quote(normalizePhoneTag(env.Phone)),
quote(env.DeviceID))
if _, err := w.exec.ExecContext(ctx, statement); err != nil {
return err
}
if phone := normalizePhoneTag(env.Phone); phone != "" {
if _, err := w.exec.ExecContext(ctx, fmt.Sprintf("ALTER TABLE %s SET TAG phone = '%s'", w.qualify(table), quote(phone))); err != nil {
return w.cache.doOnce(key, func() error {
statement := fmt.Sprintf("CREATE TABLE IF NOT EXISTS %s USING %s TAGS ('%s', '%s', '%s', '%s', '%s')",
w.qualify(table), w.qualify(stable),
quote(string(env.Protocol)),
quote(env.VehicleKey()),
quote(env.VIN),
quote(normalizePhoneTag(env.Phone)),
quote(env.DeviceID))
if _, err := w.exec.ExecContext(ctx, statement); err != nil {
return err
}
}
w.cache.mu.Lock()
w.cache.seen[key] = struct{}{}
w.cache.mu.Unlock()
return nil
if phone := normalizePhoneTag(env.Phone); phone != "" {
if _, err := w.exec.ExecContext(ctx, fmt.Sprintf("ALTER TABLE %s SET TAG phone = '%s'", w.qualify(table), quote(phone))); err != nil {
return err
}
}
return nil
})
}
func (w *Writer) ensureLocationChild(ctx context.Context, table string, env envelope.FrameEnvelope) error {
key := "vehicle_locations." + table
w.cache.mu.Lock()
_, ok := w.cache.seen[key]
w.cache.mu.Unlock()
if ok {
return w.cache.doOnce(key, func() error {
statement := fmt.Sprintf("CREATE TABLE IF NOT EXISTS %s USING %s TAGS ('%s', '%s')",
w.qualify(table),
w.qualify("vehicle_locations"),
quote(string(env.Protocol)),
quote(strings.TrimSpace(env.VIN)))
if _, err := w.exec.ExecContext(ctx, statement); err != nil {
return err
}
return nil
}
statement := fmt.Sprintf("CREATE TABLE IF NOT EXISTS %s USING %s TAGS ('%s', '%s')",
w.qualify(table),
w.qualify("vehicle_locations"),
quote(string(env.Protocol)),
quote(strings.TrimSpace(env.VIN)))
if _, err := w.exec.ExecContext(ctx, statement); err != nil {
return err
}
w.cache.mu.Lock()
w.cache.seen[key] = struct{}{}
w.cache.mu.Unlock()
return nil
})
}
func rawValues(env envelope.FrameEnvelope, rawHex string, rawText string, parsedFields string) []any {