github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/libraries/pingcap/tidb/ddl/reorg.go (about) 1 // Copyright 2015 PingCAP, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 package ddl 15 16 import ( 17 "fmt" 18 "time" 19 20 "github.com/insionng/yougam/libraries/juju/errors" 21 "github.com/insionng/yougam/libraries/pingcap/tidb/context" 22 "github.com/insionng/yougam/libraries/pingcap/tidb/kv" 23 "github.com/insionng/yougam/libraries/pingcap/tidb/meta" 24 "github.com/insionng/yougam/libraries/pingcap/tidb/model" 25 "github.com/insionng/yougam/libraries/pingcap/tidb/terror" 26 ) 27 28 var _ context.Context = &reorgContext{} 29 30 // reorgContext implements context.Context interface for reorganization use. 31 type reorgContext struct { 32 store kv.Storage 33 m map[fmt.Stringer]interface{} 34 txn kv.Transaction 35 } 36 37 func (c *reorgContext) GetTxn(forceNew bool) (kv.Transaction, error) { 38 if forceNew { 39 if c.txn != nil { 40 if err := c.txn.Commit(); err != nil { 41 return nil, errors.Trace(err) 42 } 43 c.txn = nil 44 } 45 } 46 47 if c.txn != nil { 48 return c.txn, nil 49 } 50 51 txn, err := c.store.Begin() 52 if err != nil { 53 return nil, errors.Trace(err) 54 } 55 56 c.txn = txn 57 return c.txn, nil 58 } 59 60 func (c *reorgContext) FinishTxn(rollback bool) error { 61 if c.txn == nil { 62 return nil 63 } 64 65 var err error 66 if rollback { 67 err = c.txn.Rollback() 68 } else { 69 err = c.txn.Commit() 70 } 71 72 c.txn = nil 73 74 return errors.Trace(err) 75 } 76 77 func (c *reorgContext) SetValue(key fmt.Stringer, value interface{}) { 78 c.m[key] = value 79 } 80 81 func (c *reorgContext) Value(key fmt.Stringer) interface{} { 82 return c.m[key] 83 } 84 85 func (c *reorgContext) ClearValue(key fmt.Stringer) { 86 delete(c.m, key) 87 } 88 89 func (d *ddl) newReorgContext() context.Context { 90 c := &reorgContext{ 91 store: d.store, 92 m: make(map[fmt.Stringer]interface{}), 93 } 94 95 return c 96 } 97 98 const waitReorgTimeout = 10 * time.Second 99 100 func (d *ddl) runReorgJob(f func() error) error { 101 if d.reorgDoneCh == nil { 102 // start a reorganization job 103 d.wait.Add(1) 104 d.reorgDoneCh = make(chan error, 1) 105 go func() { 106 defer d.wait.Done() 107 d.reorgDoneCh <- f() 108 }() 109 } 110 111 waitTimeout := waitReorgTimeout 112 // if d.lease is 0, we are using a local storage, 113 // and we can wait the reorganization to be done here. 114 // if d.lease > 0, we don't need to wait here because 115 // we will wait 2 * lease outer and try checking again, 116 // so we use a very little timeout here. 117 if d.lease > 0 { 118 waitTimeout = 1 * time.Millisecond 119 } 120 121 // wait reorganization job done or timeout 122 select { 123 case err := <-d.reorgDoneCh: 124 d.reorgDoneCh = nil 125 return errors.Trace(err) 126 case <-d.quitCh: 127 // we return errWaitReorgTimeout here too, so that outer loop will break. 128 return errWaitReorgTimeout 129 case <-time.After(waitTimeout): 130 // if timeout, we will return, check the owner and retry to wait job done again. 131 return errWaitReorgTimeout 132 } 133 } 134 135 func (d *ddl) isReorgRunnable(txn kv.Transaction) error { 136 if d.isClosed() { 137 // worker is closed, can't run reorganization. 138 return errors.Trace(errInvalidWorker.Gen("worker is closed")) 139 } 140 141 t := meta.NewMeta(txn) 142 owner, err := t.GetDDLJobOwner() 143 if err != nil { 144 return errors.Trace(err) 145 } else if owner == nil || owner.OwnerID != d.uuid { 146 // if no owner, we will try later, so here just return error. 147 // or another server is owner, return error too. 148 return errors.Trace(errNotOwner) 149 } 150 151 return nil 152 } 153 154 func (d *ddl) delKeysWithPrefix(prefix kv.Key) error { 155 for { 156 keys := make([]kv.Key, 0, maxBatchSize) 157 err := kv.RunInNewTxn(d.store, true, func(txn kv.Transaction) error { 158 if err1 := d.isReorgRunnable(txn); err1 != nil { 159 return errors.Trace(err1) 160 } 161 162 iter, err := txn.Seek(prefix) 163 if err != nil { 164 return errors.Trace(err) 165 } 166 167 defer iter.Close() 168 for i := 0; i < maxBatchSize; i++ { 169 if iter.Valid() && iter.Key().HasPrefix(prefix) { 170 keys = append(keys, iter.Key().Clone()) 171 err = iter.Next() 172 if err != nil { 173 return errors.Trace(err) 174 } 175 } else { 176 break 177 } 178 } 179 180 for _, key := range keys { 181 err := txn.Delete(key) 182 // must skip ErrNotExist 183 // if key doesn't exist, skip this error. 184 if err != nil && !terror.ErrorEqual(err, kv.ErrNotExist) { 185 return errors.Trace(err) 186 } 187 } 188 189 return nil 190 }) 191 192 if err != nil { 193 return errors.Trace(err) 194 } 195 196 // delete no keys, return. 197 if len(keys) == 0 { 198 return nil 199 } 200 } 201 } 202 203 type reorgInfo struct { 204 *model.Job 205 Handle int64 206 d *ddl 207 first bool 208 } 209 210 func (d *ddl) getReorgInfo(t *meta.Meta, job *model.Job) (*reorgInfo, error) { 211 var err error 212 213 info := &reorgInfo{ 214 Job: job, 215 d: d, 216 first: job.SnapshotVer == 0, 217 } 218 219 if info.first { 220 // get the current version for reorganization if we don't have 221 var ver kv.Version 222 ver, err = d.store.CurrentVersion() 223 if err != nil { 224 return nil, errors.Trace(err) 225 } else if ver.Ver <= 0 { 226 return nil, errInvalidStoreVer.Gen("invalid storage current version %d", ver.Ver) 227 } 228 229 job.SnapshotVer = ver.Ver 230 } else { 231 info.Handle, err = t.GetDDLReorgHandle(job) 232 if err != nil { 233 return nil, errors.Trace(err) 234 } 235 } 236 237 if info.Handle > 0 { 238 // we have already handled this handle, so use next 239 info.Handle++ 240 } 241 242 return info, errors.Trace(err) 243 } 244 245 func (r *reorgInfo) UpdateHandle(txn kv.Transaction, handle int64) error { 246 t := meta.NewMeta(txn) 247 return errors.Trace(t.UpdateDDLReorgHandle(r.Job, handle)) 248 }