func (d *ddl) convert2RollbackJob(t *meta.Meta, job *model.Job, tblInfo *model.TableInfo, indexInfo *model.IndexInfo) error { job.State = model.JobRollback job.Args = []interface{}{indexInfo.Name} // If add index job rollbacks in write reorganization state, its need to delete all keys which has been added. // Its work is the same as drop index job do. // The write reorganization state in add index job that likes write only state in drop index job. // So the next state is delete only state. indexInfo.State = model.StateDeleteOnly job.SchemaState = model.StateDeleteOnly err := t.UpdateTable(job.SchemaID, tblInfo) if err != nil { return errors.Trace(err) } err = kv.ErrKeyExists.Gen("Duplicate for key %s", indexInfo.Name.O) return errors.Trace(err) }
func (d *ddl) onDropIndex(t *meta.Meta, job *model.Job) error { schemaID := job.SchemaID tblInfo, err := d.getTableInfo(t, job) if err != nil { return errors.Trace(err) } var indexName model.CIStr if err = job.DecodeArgs(&indexName); err != nil { job.State = model.JobCancelled return errors.Trace(err) } var indexInfo *model.IndexInfo for _, idx := range tblInfo.Indices { if idx.Name.L == indexName.L { indexInfo = idx } } if indexInfo == nil { job.State = model.JobCancelled return ErrCantDropFieldOrKey.Gen("index %s doesn't exist", indexName) } _, err = t.GenSchemaVersion() if err != nil { return errors.Trace(err) } switch indexInfo.State { case model.StatePublic: // public -> write only job.SchemaState = model.StateWriteOnly indexInfo.State = model.StateWriteOnly err = t.UpdateTable(schemaID, tblInfo) return errors.Trace(err) case model.StateWriteOnly: // write only -> delete only job.SchemaState = model.StateDeleteOnly indexInfo.State = model.StateDeleteOnly err = t.UpdateTable(schemaID, tblInfo) return errors.Trace(err) case model.StateDeleteOnly: // delete only -> reorganization job.SchemaState = model.StateDeleteReorganization indexInfo.State = model.StateDeleteReorganization err = t.UpdateTable(schemaID, tblInfo) return errors.Trace(err) case model.StateDeleteReorganization: // reorganization -> absent tbl, err := d.getTable(schemaID, tblInfo) if err != nil { return errors.Trace(err) } err = d.runReorgJob(func() error { return d.dropTableIndex(tbl, indexInfo) }) if terror.ErrorEqual(err, errWaitReorgTimeout) { // if timeout, we should return, check for the owner and re-wait job done. return nil } if err != nil { return errors.Trace(err) } // all reorganization jobs done, drop this index newIndices := make([]*model.IndexInfo, 0, len(tblInfo.Indices)) for _, idx := range tblInfo.Indices { if idx.Name.L != indexName.L { newIndices = append(newIndices, idx) } } tblInfo.Indices = newIndices // set column index flag. dropIndexColumnFlag(tblInfo, indexInfo) if err = t.UpdateTable(schemaID, tblInfo); err != nil { return errors.Trace(err) } // finish this job job.SchemaState = model.StateNone job.State = model.JobDone return nil default: return ErrInvalidTableState.Gen("invalid table state %v", tblInfo.State) } }
func (d *ddl) onCreateIndex(t *meta.Meta, job *model.Job) error { schemaID := job.SchemaID tblInfo, err := d.getTableInfo(t, job) if err != nil { return errors.Trace(err) } var ( unique bool indexName model.CIStr indexID int64 idxColNames []*ast.IndexColName ) err = job.DecodeArgs(&unique, &indexName, &indexID, &idxColNames) if err != nil { job.State = model.JobCancelled return errors.Trace(err) } var indexInfo *model.IndexInfo for _, idx := range tblInfo.Indices { if idx.Name.L == indexName.L { if idx.State == model.StatePublic { // we already have a index with same index name job.State = model.JobCancelled return infoschema.ErrIndexExists.Gen("CREATE INDEX: index already exist %s", indexName) } indexInfo = idx } } if indexInfo == nil { indexInfo, err = buildIndexInfo(tblInfo, unique, indexName, indexID, idxColNames) if err != nil { job.State = model.JobCancelled return errors.Trace(err) } tblInfo.Indices = append(tblInfo.Indices, indexInfo) } _, err = t.GenSchemaVersion() if err != nil { return errors.Trace(err) } switch indexInfo.State { case model.StateNone: // none -> delete only job.SchemaState = model.StateDeleteOnly indexInfo.State = model.StateDeleteOnly err = t.UpdateTable(schemaID, tblInfo) return errors.Trace(err) case model.StateDeleteOnly: // delete only -> write only job.SchemaState = model.StateWriteOnly indexInfo.State = model.StateWriteOnly err = t.UpdateTable(schemaID, tblInfo) return errors.Trace(err) case model.StateWriteOnly: // write only -> reorganization job.SchemaState = model.StateWriteReorganization indexInfo.State = model.StateWriteReorganization // initialize SnapshotVer to 0 for later reorganization check. job.SnapshotVer = 0 err = t.UpdateTable(schemaID, tblInfo) return errors.Trace(err) case model.StateWriteReorganization: // reorganization -> public reorgInfo, err := d.getReorgInfo(t, job) if err != nil || reorgInfo.first { // if we run reorg firstly, we should update the job snapshot version // and then run the reorg next time. return errors.Trace(err) } var tbl table.Table tbl, err = d.getTable(schemaID, tblInfo) if err != nil { return errors.Trace(err) } err = d.runReorgJob(func() error { return d.addTableIndex(tbl, indexInfo, reorgInfo) }) if terror.ErrorEqual(err, errWaitReorgTimeout) { // if timeout, we should return, check for the owner and re-wait job done. return nil } if err != nil { return errors.Trace(err) } indexInfo.State = model.StatePublic // set column index flag. addIndexColumnFlag(tblInfo, indexInfo) if err = t.UpdateTable(schemaID, tblInfo); err != nil { return errors.Trace(err) } // finish this job job.SchemaState = model.StatePublic job.State = model.JobDone return nil default: return ErrInvalidIndexState.Gen("invalid index state %v", tblInfo.State) } }