Documentation
¶
Index ¶
- Constants
- Variables
- func ExecuteIteration(ctx context.Context, cnUUID string, cnEngine engine.Engine, ...) (err error)
- func FlushPermanentErrorMessage(ctx context.Context, cnUUID string, cnEngine engine.Engine, ...) (err error)
- func FlushStatus(ctx context.Context, cnUUID string, txn client.TxnOperator, tenantId uint32, ...) (err error)
- func HasHooks(algo string) bool
- func ISCPTaskExecutorFactory(txnEngine engine.Engine, cnTxnClient client.TxnClient, ...) func(ctx context.Context, task task.Task) (err error)
- func MarshalJobSpec(jobSpec *JobSpec) (string, error)
- func MarshalJobStatus(status *JobStatus) (string, error)
- func ProcessInitSQL(ctx context.Context, cnUUID string, cnEngine engine.Engine, ...) (err error)
- func Register(algo string, h Hooks)
- func RegisterJob(ctx context.Context, cnUUID string, txn client.TxnOperator, jobSpec *JobSpec, ...) (ok bool, err error)
- func RenameSrcTable(ctx context.Context, cnUUID string, txn client.TxnOperator, dbID, tbID uint64, ...) (err error)
- func RunCuvs(c *IndexConsumer, ctx context.Context, errch chan error, r DataRetriever, ...)
- func RunHnsw[T types.RealNumbers](c *IndexConsumer, ctx context.Context, errch chan error, r DataRetriever)
- func RunIndex(c *IndexConsumer, ctx context.Context, errch chan error, r DataRetriever)
- func UnregisterJob(ctx context.Context, cnUUID string, txn client.TxnOperator, jobID *JobID) (ok bool, err error)
- func UnregisterJobsByDBName(ctx context.Context, cnUUID string, txn client.TxnOperator, dbName string) (err error)
- func UpdateJobSpec(ctx context.Context, cnUUID string, txn client.TxnOperator, jobID *JobID, ...) (err error)
- type AtomicBatch
- type AtomicBatchRow
- type BaseIndexSqlWriter
- func (w *BaseIndexSqlWriter) CheckLastOp(op string) bool
- func (w *BaseIndexSqlWriter) Delete(ctx context.Context, row []any) error
- func (w *BaseIndexSqlWriter) Empty() bool
- func (w *BaseIndexSqlWriter) Full() bool
- func (w *BaseIndexSqlWriter) Insert(ctx context.Context, row []any) error
- func (w *BaseIndexSqlWriter) Reset()
- func (w *BaseIndexSqlWriter) Upsert(ctx context.Context, row []any) error
- type Consumer
- func NewConsumer(cnUUID string, cnEngine engine.Engine, cnTxnClient client.TxnClient, ...) (Consumer, error)
- func NewIndexConsumer(cnUUID string, cnEngine engine.Engine, cnTxnClient client.TxnClient, ...) (Consumer, error)
- func NewInteralSqlConsumer(cnUUID string, cnEngine engine.Engine, cnTxnClient client.TxnClient, ...) (Consumer, error)
- type ConsumerInfo
- type ConsumerType
- type CuvsCdcWriter
- func (w *CuvsCdcWriter) CheckLastOp(_ string) bool
- func (w *CuvsCdcWriter) ColMetaJSON() string
- func (w *CuvsCdcWriter) DbName() string
- func (w *CuvsCdcWriter) Delete(ctx context.Context, row []any) error
- func (w *CuvsCdcWriter) Dimension() int32
- func (w *CuvsCdcWriter) Empty() bool
- func (w *CuvsCdcWriter) Full() bool
- func (w *CuvsCdcWriter) IndexDef() []*plan.IndexDef
- func (w *CuvsCdcWriter) IndexName() string
- func (w *CuvsCdcWriter) Insert(ctx context.Context, row []any) error
- func (w *CuvsCdcWriter) Reset()
- func (w *CuvsCdcWriter) TblName() string
- func (w *CuvsCdcWriter) ToSql() ([]byte, error)
- func (w *CuvsCdcWriter) Upsert(ctx context.Context, row []any) error
- type CuvsSync
- type CuvsSyncFactory
- type DataRetriever
- type DataRetrieverConsumer
- type DataRetrieverImpl
- func (r *DataRetrieverImpl) Close()
- func (r *DataRetrieverImpl) GetAccountID() uint32
- func (r *DataRetrieverImpl) GetDataType() int8
- func (r *DataRetrieverImpl) GetTableID() uint64
- func (r *DataRetrieverImpl) Next() *ISCPData
- func (r *DataRetrieverImpl) SetError(err error)
- func (r *DataRetrieverImpl) SetNextBatch(data *ISCPData)
- func (r *DataRetrieverImpl) UpdateWatermark(ctx context.Context, cnUUID string, txn client.TxnOperator) error
- type FulltextSqlWriter
- type HnswSqlWriter
- func (w *HnswSqlWriter[T]) CheckLastOp(op string) bool
- func (w *HnswSqlWriter[T]) Delete(ctx context.Context, row []any) error
- func (w *HnswSqlWriter[T]) Empty() bool
- func (w *HnswSqlWriter[T]) Full() bool
- func (w *HnswSqlWriter[T]) Insert(ctx context.Context, row []any) error
- func (w *HnswSqlWriter[T]) NewSync(sqlproc *sqlexec.SqlProcess) (*hnsw.HnswSync[T], error)
- func (w *HnswSqlWriter[T]) Reset()
- func (w *HnswSqlWriter[T]) ToSql() ([]byte, error)
- func (w *HnswSqlWriter[T]) Upsert(ctx context.Context, row []any) error
- type Hooks
- type ISCPData
- type ISCPExecutorOption
- type ISCPTaskExecutor
- func (exec *ISCPTaskExecutor) Cancel() error
- func (exec *ISCPTaskExecutor) FlushWatermarkForAllTables(ttl time.Duration) error
- func (exec *ISCPTaskExecutor) GC(cleanupThreshold time.Duration) (err error)
- func (exec *ISCPTaskExecutor) GCInMemoryJob(threshold time.Duration)
- func (exec *ISCPTaskExecutor) GetJobType(accountID uint32, srcTableID uint64, jobName string) (jobType uint16, ok bool)
- func (exec *ISCPTaskExecutor) GetWatermark(accountID uint32, srcTableID uint64, jobName string) (watermark types.TS, ok bool)
- func (exec *ISCPTaskExecutor) IsRunning() bool
- func (exec *ISCPTaskExecutor) Pause() error
- func (exec *ISCPTaskExecutor) Restart() error
- func (exec *ISCPTaskExecutor) Resume() error
- func (exec *ISCPTaskExecutor) SetRpcHandleFn(fn RpcHandleFn)
- func (exec *ISCPTaskExecutor) Start() error
- func (exec *ISCPTaskExecutor) Stop()
- func (exec *ISCPTaskExecutor) String() string
- type IndexConsumer
- func (c *IndexConsumer) Algo() string
- func (c *IndexConsumer) Consume(ctx context.Context, r DataRetriever) error
- func (c *IndexConsumer) RunTxn(ctx context.Context, r DataRetriever, timeout time.Duration, ...) error
- func (c *IndexConsumer) SqlBufSendCh() <-chan []byte
- func (c *IndexConsumer) SqlWriter() IndexSqlWriter
- type IndexEntry
- type IndexSqlWriter
- func NewFulltextSqlWriter(algo string, jobID JobID, info *ConsumerInfo, tabledef *plan.TableDef, ...) (IndexSqlWriter, error)
- func NewGenericHnswSqlWriter[T types.RealNumbers](algo string, jobID JobID, info *ConsumerInfo, tabledef *plan.TableDef, ...) (IndexSqlWriter, error)
- func NewHnswSqlWriter(algo string, jobID JobID, info *ConsumerInfo, tabledef *plan.TableDef, ...) (IndexSqlWriter, error)
- func NewIndexSqlWriter(algo string, jobID JobID, info *ConsumerInfo, tabledef *plan.TableDef, ...) (IndexSqlWriter, error)
- func NewIvfflatSqlWriter(algo string, jobID JobID, info *ConsumerInfo, tabledef *plan.TableDef, ...) (IndexSqlWriter, error)
- type InitWatermark
- type IterationContext
- type IvfflatSqlWriter
- type JobEntry
- type JobID
- type JobKey
- type JobSpec
- type JobStatus
- type OutputType
- type RowIterator
- type RowType
- type RpcHandleFn
- type Schedule
- type TableEntry
- func (t *TableEntry) AddOrUpdateSinker(ctx context.Context, jobName string, jobSpec *JobSpec, jobStatus *JobStatus, ...) (newCreate bool)
- func (t *TableEntry) GetWatermark(jobName string) (watermark types.TS, ok bool)
- func (t *TableEntry) IsEmpty() bool
- func (t *TableEntry) String() string
- func (t *TableEntry) UpdateWatermark(iter *IterationContext)
- type TableInfo
- type TriggerSpec
- type Worker
Constants ¶
const ( ISCPDataType_Snapshot int8 = iota ISCPDataType_Tail )
const ( DefaultGCInterval = time.Hour DefaultGCTTL = time.Hour DefaultSyncTaskInterval = time.Second * 10 DefaultFlushWatermarkInterval = time.Hour DefaultFlushWatermarkTTL = time.Hour DefaultRetryTimes = 5 DefaultRetryInterval = time.Second DefaultRetryDuration = time.Minute * 10 )
const ( TriggerType_Invalid uint16 = iota TriggerType_Default TriggerType_AlwaysUpdate TriggerType_Timed )
const ( ISCPJobState_Invalid int8 = iota ISCPJobState_Pending ISCPJobState_Running ISCPJobState_Completed ISCPJobState_Error ISCPJobState_Canceled )
const ( JobStage_Init int8 = iota JobStage_Running )
const ( ISCPWorkerThread = 10 SubmitRetryTimes = 1000 SubmitRetryDuration = time.Hour )
const (
DefaultMaxChangeInterval = time.Minute * 30
)
const (
MAX_CDC_DATA_SIZE = 8192
)
const (
MOISCPLogTableName = catalog.MO_ISCP_LOG
)
const (
PermanentErrorThreshold = 10000
)
const (
TargetDbName = "test_intra_system_change_propagation"
)
Variables ¶
var CheckLeaseWithRetry = func( ctx context.Context, cnUUID string, txnEngine engine.Engine, cnTxnClient client.TxnClient, ) (ok bool, err error) { defer func() { if err != nil || !ok { logutil.Errorf( "ISCP-Task check lease failed, err=%v, ok=%v, cnUUID=%v", zap.Error(err), zap.Bool("ok", ok), zap.String("cnUUID", cnUUID), ) } }() err = retry( ctx, func() error { ok, err = checkLease(ctx, cnUUID, txnEngine, cnTxnClient) return err }, DefaultRetryTimes, DefaultRetryInterval, DefaultRetryDuration, ) return }
var CollectChanges = func(ctx context.Context, rel engine.Relation, fromTs, toTs types.TS, mp *mpool.MPool) (engine.ChangesHandle, error) { return rel.CollectChanges(ctx, fromTs, toTs, false, mp) }
var ExecWithResult = func( ctx context.Context, sql string, cnUUID string, txn client.TxnOperator, ) (executor.Result, error) { v, ok := moruntime.ServiceRuntime(cnUUID).GetGlobalVariables(moruntime.InternalSQLExecutor) if !ok { panic("missing lock service") } exec := v.(executor.SQLExecutor) opts := executor.Options{}. WithDisableIncrStatement(). WithTxn(txn) return exec.Exec(ctx, sql, opts) }
var FlushJobStatusOnIterationState = func( ctx context.Context, cnUUID string, cnEngine engine.Engine, cnTxnClient client.TxnClient, accountID uint32, tableID uint64, jobNames []string, jobIDs []uint64, lsns []uint64, jobStatuses []*JobStatus, watermark types.TS, state int8, prevLSN []uint64, ) (err error) { ctx = context.WithValue(ctx, defines.TenantIDKey{}, catalog.System_Account) ctx, cancel := context.WithTimeout(ctx, time.Minute*5) defer cancel() txnWriter, err := getTxn(ctx, cnEngine, cnTxnClient, "iscp iteration") if err != nil { return } defer func() { if err != nil { err = errors.Join(err, txnWriter.Rollback(ctx)) } else { err = txnWriter.Commit(ctx) } if err != nil { logutil.Error( "ISCP-Task flush job status failed", zap.Uint32("tenantID", accountID), zap.Uint64("tableID", tableID), zap.Strings("jobNames", jobNames), zap.Int8("state", state), zap.Error(err), ) } }() for i := range jobNames { jobStatuses[i].LSN = lsns[i] err = FlushStatus( ctx, cnUUID, txnWriter, accountID, tableID, jobNames[i], jobIDs[i], jobStatuses[i], watermark, state, prevLSN[i], ) if err != nil { return } } return }
var GetJobSpecs = func( ctx context.Context, cnUUID string, cnTxnClient client.TxnClient, cnEngine engine.Engine, txn client.TxnOperator, tenantId uint32, tableID uint64, jobName []string, lsns []uint64, watermark types.TS, jobStatuses []*JobStatus, jobIDs []uint64, ) (jobSpec []*JobSpec, prevStatus []*JobStatus, err error) { var buf bytes.Buffer buf.WriteString("SELECT job_spec, job_status FROM mo_catalog.mo_iscp_log WHERE") for i, jobName := range jobName { if i > 0 { buf.WriteString(" OR") } buf.WriteString(fmt.Sprintf(" (account_id = %d AND table_id = %d AND job_name = '%s' AND job_id = %d)", tenantId, tableID, jobName, jobIDs[i])) } sql := buf.String() execResult, err := ExecWithResult(ctx, sql, cnUUID, txn) if err != nil { return } prevLSNs := make([]uint64, len(jobName)) for i := range jobName { prevLSNs[i] = lsns[i] - 1 } defer execResult.Close() jobSpec = make([]*JobSpec, len(jobName)) prevStatus = make([]*JobStatus, len(jobName)) execResult.ReadRows(func(rows int, cols []*vector.Vector) bool { if rows != len(jobName) { errMsg := fmt.Sprintf("invalid rows %d, expected %d", rows, len(jobName)) FlushPermanentErrorMessage( ctx, cnUUID, cnEngine, cnTxnClient, tenantId, tableID, jobName, jobIDs, lsns, jobStatuses, types.MaxTs(), errMsg, prevLSNs, ) } for i := 0; i < rows; i++ { jobSpec[i], err = UnmarshalJobSpec([]byte(cols[0].GetStringAt(i))) if err != nil { return false } prevStatus[i], err = UnmarshalJobStatus([]byte(cols[1].GetStringAt(i))) if err != nil { return false } } return true }) return }
Functions ¶
func ExecuteIteration ¶
func FlushPermanentErrorMessage ¶
func FlushPermanentErrorMessage( ctx context.Context, cnUUID string, cnEngine engine.Engine, cnTxnClient client.TxnClient, accountID uint32, tableID uint64, jobNames []string, jobIDs []uint64, lsns []uint64, jobStatuses []*JobStatus, watermark types.TS, errMsg string, prevLSN []uint64, ) (err error)
func FlushStatus ¶
func ISCPTaskExecutorFactory ¶
func MarshalJobSpec ¶
func MarshalJobStatus ¶
func ProcessInitSQL ¶
func Register ¶
Register installs an ISCP hook for an algorithm. Algo names are case-insensitive (lower-cased on store). Intended to be called from pkg/indexplugin/all init() bodies; panics on duplicate registration.
func RegisterJob ¶
func RegisterJob( ctx context.Context, cnUUID string, txn client.TxnOperator, jobSpec *JobSpec, jobID *JobID, startFromNow bool, ) (ok bool, err error)
RegisterJob create jobs. return true if create, return false if task already exists, return error when error JobID.DBName: required, the name of the database. JobID.TableName: required, the name of the table. JobID.JobName: required, used to distinguish jobs on the same table.
Each job on the same table must have a unique job name. If a duplicate job name is encountered, the returned 'ok' will be false, and the original job will be kept without creating a new one.
JobSpec.ConsumerInfo.ConsumerType: required, the type of downstream consumer.
The consumer will be generated according to this type during synchronization.
JobSpec.ConsumerInfo.ColumnNames: optional, currently not effective (TODO).
Specifies the columns needed by the downstream consumer. If empty, the consumer will receive all columns of the table.
JobSpec.Priority: optional, the priority for acquiring a worker during execution, currently not effective (TODO). JobSpec.TriggerSpec.JobType: optional, if not set, it will be set to TriggerType_Default. JobSpec.TriggerSpec.Schedule: should be filled according to the triggertype.
For example, for TriggerType_Default, no need to fill; for TriggerType_Timed, Interval and share should be specified.
func RenameSrcTable ¶
func RunCuvs ¶
func RunCuvs(c *IndexConsumer, ctx context.Context, errch chan error, r DataRetriever, factory CuvsSyncFactory)
RunCuvs drives one ISCP consumer iteration for cuvs-backed vector indexes (CAGRA, IVF-PQ). It reads raw EncodeEventRecord byte chunks from the consumer's send channel — no JSON marshal/unmarshal — and appends them straight into the sync's pending buffer via AppendRecords. On channel close it flushes via Save and updates the tail watermark.
Used as the Run implementation by CAGRA and IVF-PQ plugin Hooks. HNSW stays on RunHnsw[T] / VectorIndexCdc[T] — different sync architecture (in-memory graph mutation, no event log).
func RunHnsw ¶
func RunHnsw[T types.RealNumbers](c *IndexConsumer, ctx context.Context, errch chan error, r DataRetriever)
RunHnsw drives one ISCP consumer iteration for HNSW indexes. It reads JSON CDC blobs from the writer's send channel, applies them to an in-memory HnswSync graph via Update, then flushes the model to the hidden tables via Save when the channel closes. Used as the Run implementation by HNSW's plugin Hooks.
The generic parameter T is the vector element type (float32 or float64), matched against the writer type at the call site.
func RunIndex ¶
func RunIndex(c *IndexConsumer, ctx context.Context, errch chan error, r DataRetriever)
RunIndex drives one ISCP consumer iteration for SQL-based index algorithms (fulltext, IVF-FLAT). It drains SQL statements from the consumer's send channel and executes them against the hidden tables, committing each statement individually for snapshot data and under one long-lived transaction for tail data. Used as the default Run implementation by plugin Hooks whose writer produces SQL rather than a JSON CDC blob.
func UnregisterJob ¶
func UnregisterJob( ctx context.Context, cnUUID string, txn client.TxnOperator, jobID *JobID, ) (ok bool, err error)
return true if delete success, return false if no task found, return error when delete failed.
func UnregisterJobsByDBName ¶
func UpdateJobSpec ¶
Types ¶
type AtomicBatch ¶
type AtomicBatch struct {
Mp *mpool.MPool
Batches []*batch.Batch
Rows *btree.BTreeG[AtomicBatchRow]
}
AtomicBatch holds batches from [Tail_wip,...,Tail_done] or [Tail_done]. These batches have atomicity
func NewAtomicBatch ¶
func NewAtomicBatch(mp *mpool.MPool) *AtomicBatch
func (*AtomicBatch) Close ¶
func (bat *AtomicBatch) Close()
func (*AtomicBatch) GetRowIterator ¶
func (bat *AtomicBatch) GetRowIterator() RowIterator
type AtomicBatchRow ¶
func (AtomicBatchRow) Less ¶
func (row AtomicBatchRow) Less(other AtomicBatchRow) bool
type BaseIndexSqlWriter ¶
type BaseIndexSqlWriter struct {
// contains filtered or unexported fields
}
Base implementation of IVFFLAT and FULLTEXT. Their implementation are simliar.
func (*BaseIndexSqlWriter) CheckLastOp ¶
func (w *BaseIndexSqlWriter) CheckLastOp(op string) bool
return true when last op is empty or last op == current op
func (*BaseIndexSqlWriter) Delete ¶
func (w *BaseIndexSqlWriter) Delete(ctx context.Context, row []any) error
func (*BaseIndexSqlWriter) Empty ¶
func (w *BaseIndexSqlWriter) Empty() bool
func (*BaseIndexSqlWriter) Full ¶
func (w *BaseIndexSqlWriter) Full() bool
Implementation of Base Index SqlWriter
func (*BaseIndexSqlWriter) Insert ¶
func (w *BaseIndexSqlWriter) Insert(ctx context.Context, row []any) error
func (*BaseIndexSqlWriter) Reset ¶
func (w *BaseIndexSqlWriter) Reset()
type Consumer ¶
type Consumer interface {
Consume(context.Context, DataRetriever) error
}
func NewConsumer ¶
func NewIndexConsumer ¶
type ConsumerInfo ¶
type ConsumerType ¶
type ConsumerType int8
const ( ConsumerType_IndexSync ConsumerType = iota ConsumerType_CNConsumer ConsumerType_CustomizedStart = 1000 )
type CuvsCdcWriter ¶
type CuvsCdcWriter struct {
// contains filtered or unexported fields
}
CuvsCdcWriter is the shared CDC writer for cuvs-backed vector indexes (CAGRA, IVF-PQ). One instance per (table, index) pair, constructed once at NewIndexConsumer time.
Buffers CDC row events as a sequence of EncodeEventRecord byte chunks — the same binary format CagraSync.Save / IvfpqSync.Save eventually flushes to the storage table. No JSON, no VectorIndexCdc[T] round-trip.
Despite the "Writer" name (and the IndexSqlWriter interface it satisfies), the output is not SQL — it's the binary event-record stream consumed by RunCuvs → sync.AppendRecords.
INSERT and UPSERT are encoded with distinct op codes (CdcOpInsert / CdcOpUpsert) sharing the same payload layout. Replay handles them identically (idempotent overflow-map write — safe under MO's duplicate / replay-from-corruption UPSERT semantics), but the chunk frame's n_inserts counter tallies only CdcOpInsert so the idxcron gate sees a strict lower bound on growth. This mirrors HNSW's pattern (HnswSqlWriter preserves UPSERT distinctly all the way through). The synchronous in-process callers (CagraSync.Update) still emit DELETE+INSERT pairs as their own thing — that's a different code path from this CDC writer.
func NewCuvsCdcWriter ¶
func NewCuvsCdcWriter(algoName, dbName, tblName, indexName string, tabledef *plan.TableDef, indexdefs []*plan.IndexDef) (*CuvsCdcWriter, error)
NewCuvsCdcWriter constructs a CuvsCdcWriter from the per-(table, index) def. algoName is for diagnostics only (the writer does not switch on it); dbName/tblName/indexName are typically pulled from the ISCP ConsumerInfo at the call site.
Both CAGRA and IVF-PQ on cuvs are fp32-only with a bigint PK; this constructor enforces both shapes.
func (*CuvsCdcWriter) CheckLastOp ¶
func (w *CuvsCdcWriter) CheckLastOp(_ string) bool
func (*CuvsCdcWriter) ColMetaJSON ¶
func (w *CuvsCdcWriter) ColMetaJSON() string
func (*CuvsCdcWriter) DbName ¶
func (w *CuvsCdcWriter) DbName() string
Accessors used by per-algo Hooks.Run impls to build their algo's sync object (CagraSync / IvfpqSync) — passed the same dbName etc. the writer was constructed with so writer and sync agree on layout (especially the colMetaJSON for INCLUDE columns).
func (*CuvsCdcWriter) Delete ¶
func (w *CuvsCdcWriter) Delete(ctx context.Context, row []any) error
Delete encodes a DELETE event. Only the primary key is consulted — the delete-row payload from ISCP carries just row[0]=pk.
func (*CuvsCdcWriter) Dimension ¶
func (w *CuvsCdcWriter) Dimension() int32
func (*CuvsCdcWriter) Empty ¶
func (w *CuvsCdcWriter) Empty() bool
func (*CuvsCdcWriter) Full ¶
func (w *CuvsCdcWriter) Full() bool
func (*CuvsCdcWriter) IndexDef ¶
func (w *CuvsCdcWriter) IndexDef() []*plan.IndexDef
func (*CuvsCdcWriter) IndexName ¶
func (w *CuvsCdcWriter) IndexName() string
func (*CuvsCdcWriter) Reset ¶
func (w *CuvsCdcWriter) Reset()
func (*CuvsCdcWriter) TblName ¶
func (w *CuvsCdcWriter) TblName() string
func (*CuvsCdcWriter) ToSql ¶
func (w *CuvsCdcWriter) ToSql() ([]byte, error)
ToSql returns a copy of the accumulated event-record bytes. The naming is historical (IndexSqlWriter interface). Caller takes ownership of the returned slice; framing immediately calls Reset() so the writer's internal buffer is reused for the next batch.
type CuvsSync ¶
type CuvsSync interface {
AppendRecords(sqlproc *sqlexec.SqlProcess, recordBytes []byte) error
Save(sqlproc *sqlexec.SqlProcess) error
Destroy()
}
CuvsSync is the algorithm-side interface that RunCuvs drives. cuvs vector indexes (CAGRA, IVF-PQ) implement this via their per-package CagraSync / IvfpqSync types (under //go:build gpu — pkg/iscp is CPU-safe).
Semantics:
- AppendRecords appends a writer-produced byte chunk (one or more EncodeEventRecord records concatenated, no JSON wrapping) to the sync's pending buffer.
- Save flushes the pending records to the storage table as tag=1 event chunks. Called once at channel close.
- Destroy releases any cuvs-side resources. Called via defer.
type CuvsSyncFactory ¶
type CuvsSyncFactory func(sqlproc *sqlexec.SqlProcess) (CuvsSync, error)
CuvsSyncFactory constructs a CuvsSync inside the txn provided by the runner. Plugin Hooks.Run impls pass a closure that calls cagra.NewCagraSync / ivfpq.NewIvfpqSync; the factory is what keeps the GPU-tagged types out of pkg/iscp.
type DataRetriever ¶
type DataRetrieverConsumer ¶
type DataRetrieverConsumer interface {
DataRetriever
SetNextBatch(*ISCPData)
SetError(error)
Close()
}
type DataRetrieverImpl ¶
type DataRetrieverImpl struct {
// contains filtered or unexported fields
}
func NewDataRetriever ¶
func (*DataRetrieverImpl) Close ¶
func (r *DataRetrieverImpl) Close()
func (*DataRetrieverImpl) GetAccountID ¶
func (r *DataRetrieverImpl) GetAccountID() uint32
func (*DataRetrieverImpl) GetDataType ¶
func (r *DataRetrieverImpl) GetDataType() int8
func (*DataRetrieverImpl) GetTableID ¶
func (r *DataRetrieverImpl) GetTableID() uint64
func (*DataRetrieverImpl) Next ¶
func (r *DataRetrieverImpl) Next() *ISCPData
func (*DataRetrieverImpl) SetError ¶
func (r *DataRetrieverImpl) SetError(err error)
after error occurs, the data retriever won't consume any more data
func (*DataRetrieverImpl) SetNextBatch ¶
func (r *DataRetrieverImpl) SetNextBatch(data *ISCPData)
func (*DataRetrieverImpl) UpdateWatermark ¶
func (r *DataRetrieverImpl) UpdateWatermark(ctx context.Context, cnUUID string, txn client.TxnOperator) error
type FulltextSqlWriter ¶
type FulltextSqlWriter struct {
BaseIndexSqlWriter
// contains filtered or unexported fields
}
Fulltext Sql Writer. Only one hidden secondary index table
func (*FulltextSqlWriter) ToSql ¶
func (w *FulltextSqlWriter) ToSql() ([]byte, error)
with src as (select cast(serial(cast(column_0 as bigint), cast(column_1 as bigint)) as varchar) as id, column_2 as body, column_3 as title from (values row(1, 2, 'body', 'title'), row(2, 3, 'body is heavy', 'I do not know'))) select f.* from src cross apply fulltext_index_tokenize('{"parser":"ngram"}', 61, id, body, title) as f;
type HnswSqlWriter ¶
type HnswSqlWriter[T types.RealNumbers] struct { // contains filtered or unexported fields }
Hnsw Sql Writer. Use the vectorindex.VectorIndeXCdc JSON format
func (*HnswSqlWriter[T]) CheckLastOp ¶
func (w *HnswSqlWriter[T]) CheckLastOp(op string) bool
func (*HnswSqlWriter[T]) Delete ¶
func (w *HnswSqlWriter[T]) Delete(ctx context.Context, row []any) error
func (*HnswSqlWriter[T]) Empty ¶
func (w *HnswSqlWriter[T]) Empty() bool
func (*HnswSqlWriter[T]) Full ¶
func (w *HnswSqlWriter[T]) Full() bool
func (*HnswSqlWriter[T]) Insert ¶
func (w *HnswSqlWriter[T]) Insert(ctx context.Context, row []any) error
func (*HnswSqlWriter[T]) NewSync ¶
func (w *HnswSqlWriter[T]) NewSync(sqlproc *sqlexec.SqlProcess) (*hnsw.HnswSync[T], error)
func (*HnswSqlWriter[T]) Reset ¶
func (w *HnswSqlWriter[T]) Reset()
func (*HnswSqlWriter[T]) ToSql ¶
func (w *HnswSqlWriter[T]) ToSql() ([]byte, error)
type Hooks ¶
type Hooks interface {
// NewSqlWriter constructs the per-(table,index) writer that turns
// CDC row events into either a SQL statement (fulltext / ivfflat)
// or a JSON CDC blob (hnsw / cagra / ivfpq). The returned writer
// satisfies IndexSqlWriter; the caller takes ownership.
NewSqlWriter(jobID JobID, info *ConsumerInfo,
tabledef *plan.TableDef, indexdefs []*plan.IndexDef) (IndexSqlWriter, error)
// Run drives one consumer iteration. SQL-based algorithms delegate
// to the shared RunIndex helper; HNSW / CAGRA / IVF-PQ run their
// algorithm-specific Update+Save loop driven by the writer's CDC
// JSON output. The consumer goroutine calls this once per iteration
// and the implementation is responsible for draining sqlBufSendCh
// until close, then updating watermarks (for tail data) and
// reporting errors via errch.
Run(c *IndexConsumer, ctx context.Context, errch chan error, r DataRetriever)
}
Hooks is the per-algorithm ISCP hook layer. One implementation per index type (HNSW, IVF-FLAT, fulltext, CAGRA, IVF-PQ). Hooks are registered from pkg/indexplugin/all via Register; pkg/iscp looks them up by algo string from NewIndexConsumer / NewIndexSqlWriter.
Implementations live alongside the algorithm's other plugin hooks at pkg/<algopkg>/plugin/iscp/ (e.g. pkg/vectorindex/hnsw/plugin/iscp/), not in pkg/iscp — keeps algorithm-specific code (and its build-tag constraints, where applicable) out of the ISCP framework.
type ISCPData ¶
type ISCPData struct {
// contains filtered or unexported fields
}
func NewISCPData ¶
func NewISCPData( noMoreData bool, insertBatch *AtomicBatch, deleteBatch *AtomicBatch, err error, ) *ISCPData
type ISCPExecutorOption ¶
type ISCPTaskExecutor ¶
type ISCPTaskExecutor struct {
// contains filtered or unexported fields
}
Intra-System Change Propagation Task Executor iscp executor manages iterations, updates watermarks, and updates the iscp table.
func NewISCPTaskExecutor ¶
func (*ISCPTaskExecutor) Cancel ¶
func (exec *ISCPTaskExecutor) Cancel() error
func (*ISCPTaskExecutor) FlushWatermarkForAllTables ¶
func (exec *ISCPTaskExecutor) FlushWatermarkForAllTables(ttl time.Duration) error
func (*ISCPTaskExecutor) GC ¶
func (exec *ISCPTaskExecutor) GC(cleanupThreshold time.Duration) (err error)
func (*ISCPTaskExecutor) GCInMemoryJob ¶
func (exec *ISCPTaskExecutor) GCInMemoryJob(threshold time.Duration)
func (*ISCPTaskExecutor) GetJobType ¶
func (exec *ISCPTaskExecutor) GetJobType(accountID uint32, srcTableID uint64, jobName string) (jobType uint16, ok bool)
For UT
func (*ISCPTaskExecutor) GetWatermark ¶
func (exec *ISCPTaskExecutor) GetWatermark(accountID uint32, srcTableID uint64, jobName string) (watermark types.TS, ok bool)
For UT
func (*ISCPTaskExecutor) IsRunning ¶
func (exec *ISCPTaskExecutor) IsRunning() bool
func (*ISCPTaskExecutor) Pause ¶
func (exec *ISCPTaskExecutor) Pause() error
func (*ISCPTaskExecutor) Restart ¶
func (exec *ISCPTaskExecutor) Restart() error
func (*ISCPTaskExecutor) Resume ¶
func (exec *ISCPTaskExecutor) Resume() error
func (*ISCPTaskExecutor) SetRpcHandleFn ¶
func (exec *ISCPTaskExecutor) SetRpcHandleFn(fn RpcHandleFn)
func (*ISCPTaskExecutor) Start ¶
func (exec *ISCPTaskExecutor) Start() error
func (*ISCPTaskExecutor) Stop ¶
func (exec *ISCPTaskExecutor) Stop()
func (*ISCPTaskExecutor) String ¶
func (exec *ISCPTaskExecutor) String() string
type IndexConsumer ¶
type IndexConsumer struct {
// contains filtered or unexported fields
}
IndexConsumer
func (*IndexConsumer) Algo ¶
func (c *IndexConsumer) Algo() string
Algo returns the algorithm string this consumer's writer was built for. Useful for diagnostics inside plugin Hooks.
func (*IndexConsumer) Consume ¶
func (c *IndexConsumer) Consume(ctx context.Context, r DataRetriever) error
func (*IndexConsumer) RunTxn ¶
func (c *IndexConsumer) RunTxn( ctx context.Context, r DataRetriever, timeout time.Duration, cb func(sqlproc *sqlexec.SqlProcess) error, ) error
RunTxn wraps sqlexec.RunTxnWithSqlContext bound to this consumer's connection plumbing (engine, txn client, CN UUID) and the retriever's account ID. Plugin Hooks.Run impls living outside pkg/iscp use this to execute SQL / drive a sync object inside a properly scoped txn without needing access to the consumer's private fields.
func (*IndexConsumer) SqlBufSendCh ¶
func (c *IndexConsumer) SqlBufSendCh() <-chan []byte
SqlBufSendCh exposes the channel on which the framing layer delivers writer SQL / CDC JSON blobs. Plugin Hooks.Run impls read from this channel and stop when it closes (signalling end-of-iteration).
func (*IndexConsumer) SqlWriter ¶
func (c *IndexConsumer) SqlWriter() IndexSqlWriter
SqlWriter returns the writer this consumer is paired with. Used by plugin Hooks.Run impls that need to dispatch on the writer's concrete type (e.g. HNSW picking RunHnsw[float32] vs [float64]).
type IndexEntry ¶
type IndexEntry struct {
// contains filtered or unexported fields
}
IndexConsumer
type IndexSqlWriter ¶
type IndexSqlWriter interface {
CheckLastOp(op string) bool
Upsert(ctx context.Context, row []any) error
Insert(ctx context.Context, row []any) error
Delete(ctx context.Context, row []any) error
Full() bool
ToSql() ([]byte, error)
Reset()
Empty() bool
}
IndexSqlWriter interface
func NewFulltextSqlWriter ¶
func NewFulltextSqlWriter(algo string, jobID JobID, info *ConsumerInfo, tabledef *plan.TableDef, indexdef []*plan.IndexDef) (IndexSqlWriter, error)
New Fulltext Sql Writer
func NewGenericHnswSqlWriter ¶
func NewGenericHnswSqlWriter[T types.RealNumbers](algo string, jobID JobID, info *ConsumerInfo, tabledef *plan.TableDef, indexdef []*plan.IndexDef) (IndexSqlWriter, error)
func NewHnswSqlWriter ¶
func NewHnswSqlWriter(algo string, jobID JobID, info *ConsumerInfo, tabledef *plan.TableDef, indexdef []*plan.IndexDef) (IndexSqlWriter, error)
Implementation of HNSW Sql writer
func NewIndexSqlWriter ¶
func NewIndexSqlWriter(algo string, jobID JobID, info *ConsumerInfo, tabledef *plan.TableDef, indexdef []*plan.IndexDef) (IndexSqlWriter, error)
NewIndexSqlWriter dispatches to the per-algorithm writer via the iscp Hooks registry. Replaces the hardcoded fulltext / ivfflat / hnsw switch — new algorithms register a Hooks impl (see pkg/sql/compile/iscp_register.go) and slot in automatically.
func NewIvfflatSqlWriter ¶
func NewIvfflatSqlWriter(algo string, jobID JobID, info *ConsumerInfo, tabledef *plan.TableDef, indexdef []*plan.IndexDef) (IndexSqlWriter, error)
Implementation of Ivfflat Sql writer
type InitWatermark ¶
type IterationContext ¶
type IterationContext struct {
// contains filtered or unexported fields
}
func NewIterationContext ¶
func (*IterationContext) String ¶
func (iterCtx *IterationContext) String() string
type IvfflatSqlWriter ¶
type IvfflatSqlWriter struct {
BaseIndexSqlWriter
// contains filtered or unexported fields
}
Ivfflat Sql writer. Three hidden secondary index tables
func (*IvfflatSqlWriter) ToSql ¶
func (w *IvfflatSqlWriter) ToSql() ([]byte, error)
REPLACE INTO __mo_index_secondary_0197786c-285f-70cb-9337-e484a3ff92c4(__mo_index_centroid_fk_version, __mo_index_centroid_fk_id, __mo_index_pri_col, __mo_index_centroid_fk_entry) with centroid as (select * from __mo_index_secondary_0197786c-285f-70bb-b277-2cef56da590a where __mo_index_centroid_version = 0), src as (select column_0 as id, cast(column_1 as vecf32(3)) as embed from (values row(2005,'[0.4532634, 0.7297859, 0.48885703]'), row(2009, '[0.68150306, 0.6950923, 0.16590895] '))) select __mo_index_centroid_version, __mo_index_centroid_id, id, embed from src centroidx('vector_l2_ops') join centroid using (__mo_index_centroid, embed);
type JobEntry ¶
type JobEntry struct {
// contains filtered or unexported fields
}
Intra-System Change Propagation Job Entry
func NewJobEntry ¶
func (*JobEntry) IsInitedAndFinished ¶
func (*JobEntry) StringLocked ¶
type JobSpec ¶
type JobSpec struct {
Priority int8
ConsumerInfo
TriggerSpec
}
func UnmarshalJobSpec ¶
type JobStatus ¶
type JobStatus struct {
LSN uint64
Stage int8
TaskID uint64
From types.TS
To types.TS
StartAt types.TS
EndAt types.TS
ErrorCode int
ErrorMsg string
}
func UnmarshalJobStatus ¶
func (*JobStatus) PermanentlyFailed ¶
type OutputType ¶
type OutputType int8
const ( OutputTypeSnapshot OutputType = iota OutputTypeTail )
func (OutputType) String ¶
func (t OutputType) String() string
type RowIterator ¶
type RpcHandleFn ¶
type RpcHandleFn func( ctx context.Context, meta txn.TxnMeta, req *cmd_util.GetChangedTableListReq, resp *cmd_util.GetChangedTableListResp, ) (func(), error)
type TableEntry ¶
type TableEntry struct {
// contains filtered or unexported fields
}
Intra-System Change Propagation Table Entry
func NewTableEntry ¶
func NewTableEntry( exec *ISCPTaskExecutor, accountID uint32, dbID, tableID uint64, dbName, tableName string, ) *TableEntry
func (*TableEntry) AddOrUpdateSinker ¶
func (*TableEntry) GetWatermark ¶
func (t *TableEntry) GetWatermark(jobName string) (watermark types.TS, ok bool)
for UT
func (*TableEntry) IsEmpty ¶
func (t *TableEntry) IsEmpty() bool
func (*TableEntry) String ¶
func (t *TableEntry) String() string
func (*TableEntry) UpdateWatermark ¶
func (t *TableEntry) UpdateWatermark(iter *IterationContext)
type TriggerSpec ¶
func (*TriggerSpec) GetType ¶
func (triggerSpec *TriggerSpec) GetType() uint16
func (*TriggerSpec) Init ¶
func (triggerSpec *TriggerSpec) Init()