You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

401 lines
8.9 KiB

  1. // Package keymigrate translates all legacy formatted keys to their
  2. // new components.
  3. //
  4. // The key migration operation as implemented provides a potential
  5. // model for database migration operations. Crucially, the migration
  6. // as implemented does not depend on any tendermint code.
  7. package keymigrate
  8. import (
  9. "bytes"
  10. "context"
  11. "encoding/binary"
  12. "encoding/hex"
  13. "fmt"
  14. "math/rand"
  15. "runtime"
  16. "strconv"
  17. "sync"
  18. "github.com/google/orderedcode"
  19. dbm "github.com/tendermint/tm-db"
  20. )
  21. type (
  22. keyID []byte
  23. migrateFunc func(keyID) (keyID, error)
  24. )
  25. func getAllLegacyKeys(db dbm.DB) ([]keyID, error) {
  26. out := []keyID{}
  27. iter, err := db.Iterator(nil, nil)
  28. if err != nil {
  29. return nil, err
  30. }
  31. for ; iter.Valid(); iter.Next() {
  32. k := iter.Key()
  33. // make sure it's a key with a legacy format, and skip
  34. // all other keys, to make it safe to resume the migration.
  35. if !keyIsLegacy(k) {
  36. continue
  37. }
  38. // there's inconsistency around tm-db's handling of
  39. // key copies.
  40. nk := make([]byte, len(k))
  41. copy(nk, k)
  42. out = append(out, nk)
  43. }
  44. if err = iter.Error(); err != nil {
  45. return nil, err
  46. }
  47. if err = iter.Close(); err != nil {
  48. return nil, err
  49. }
  50. return out, nil
  51. }
  52. func makeKeyChan(keys []keyID) <-chan keyID {
  53. out := make(chan keyID, len(keys))
  54. defer close(out)
  55. for _, key := range keys {
  56. out <- key
  57. }
  58. return out
  59. }
  60. func keyIsLegacy(key keyID) bool {
  61. for _, prefix := range []keyID{
  62. // core "store"
  63. keyID("consensusParamsKey:"),
  64. keyID("abciResponsesKey:"),
  65. keyID("validatorsKey:"),
  66. keyID("stateKey"),
  67. keyID("H:"),
  68. keyID("P:"),
  69. keyID("C:"),
  70. keyID("SC:"),
  71. keyID("BH:"),
  72. // light
  73. keyID("size"),
  74. keyID("lb/"),
  75. // evidence
  76. keyID([]byte{0x00}),
  77. keyID([]byte{0x01}),
  78. // tx index
  79. keyID("tx.height/"),
  80. keyID("tx.hash/"),
  81. } {
  82. if bytes.HasPrefix(key, prefix) {
  83. return true
  84. }
  85. }
  86. // this means it's a tx index...
  87. if bytes.Count(key, []byte("/")) >= 3 {
  88. return true
  89. }
  90. return keyIsHash(key)
  91. }
  92. func keyIsHash(key keyID) bool {
  93. return len(key) == 32 && !bytes.Contains(key, []byte("/"))
  94. }
  95. func migarateKey(key keyID) (keyID, error) {
  96. switch {
  97. case bytes.HasPrefix(key, keyID("H:")):
  98. val, err := strconv.Atoi(string(key[2:]))
  99. if err != nil {
  100. return nil, err
  101. }
  102. return orderedcode.Append(nil, int64(0), int64(val))
  103. case bytes.HasPrefix(key, keyID("P:")):
  104. parts := bytes.Split(key[2:], []byte(":"))
  105. if len(parts) != 2 {
  106. return nil, fmt.Errorf("block parts key has %d rather than 2 components",
  107. len(parts))
  108. }
  109. valOne, err := strconv.Atoi(string(parts[0]))
  110. if err != nil {
  111. return nil, err
  112. }
  113. valTwo, err := strconv.Atoi(string(parts[1]))
  114. if err != nil {
  115. return nil, err
  116. }
  117. return orderedcode.Append(nil, int64(1), int64(valOne), int64(valTwo))
  118. case bytes.HasPrefix(key, keyID("C:")):
  119. val, err := strconv.Atoi(string(key[2:]))
  120. if err != nil {
  121. return nil, err
  122. }
  123. return orderedcode.Append(nil, int64(2), int64(val))
  124. case bytes.HasPrefix(key, keyID("SC:")):
  125. val, err := strconv.Atoi(string(key[3:]))
  126. if err != nil {
  127. return nil, err
  128. }
  129. return orderedcode.Append(nil, int64(3), int64(val))
  130. case bytes.HasPrefix(key, keyID("BH:")):
  131. val, err := strconv.Atoi(string(key[3:]))
  132. if err != nil {
  133. return nil, err
  134. }
  135. return orderedcode.Append(nil, int64(4), int64(val))
  136. case bytes.HasPrefix(key, keyID("validatorsKey:")):
  137. val, err := strconv.Atoi(string(key[14:]))
  138. if err != nil {
  139. return nil, err
  140. }
  141. return orderedcode.Append(nil, int64(5), int64(val))
  142. case bytes.HasPrefix(key, keyID("consensusParamsKey:")):
  143. val, err := strconv.Atoi(string(key[19:]))
  144. if err != nil {
  145. return nil, err
  146. }
  147. return orderedcode.Append(nil, int64(6), int64(val))
  148. case bytes.HasPrefix(key, keyID("abciResponsesKey:")):
  149. val, err := strconv.Atoi(string(key[17:]))
  150. if err != nil {
  151. return nil, err
  152. }
  153. return orderedcode.Append(nil, int64(7), int64(val))
  154. case bytes.HasPrefix(key, keyID("stateKey")):
  155. return orderedcode.Append(nil, int64(8))
  156. case bytes.HasPrefix(key, []byte{0x00}): // committed evidence
  157. return convertEvidence(key, 9)
  158. case bytes.HasPrefix(key, []byte{0x01}): // pending evidence
  159. return convertEvidence(key, 10)
  160. case bytes.HasPrefix(key, keyID("lb/")):
  161. if len(key) < 24 {
  162. return nil, fmt.Errorf("light block evidence %q in invalid format", string(key))
  163. }
  164. val, err := strconv.Atoi(string(key[len(key)-20:]))
  165. if err != nil {
  166. return nil, err
  167. }
  168. return orderedcode.Append(nil, int64(11), int64(val))
  169. case bytes.HasPrefix(key, keyID("size")):
  170. return orderedcode.Append(nil, int64(12))
  171. case bytes.HasPrefix(key, keyID("tx.height")):
  172. parts := bytes.Split(key, []byte("/"))
  173. if len(parts) != 4 {
  174. return nil, fmt.Errorf("key has %d parts rather than 4", len(parts))
  175. }
  176. parts = parts[1:] // drop prefix
  177. elems := make([]interface{}, 0, len(parts)+1)
  178. elems = append(elems, "tx.height")
  179. for idx, pt := range parts {
  180. val, err := strconv.Atoi(string(pt))
  181. if err != nil {
  182. return nil, err
  183. }
  184. if idx == 0 {
  185. elems = append(elems, fmt.Sprintf("%d", val))
  186. } else {
  187. elems = append(elems, int64(val))
  188. }
  189. }
  190. return orderedcode.Append(nil, elems...)
  191. case bytes.Count(key, []byte("/")) >= 3: // tx indexer
  192. parts := bytes.Split(key, []byte("/"))
  193. elems := make([]interface{}, 0, 4)
  194. if len(parts) == 4 {
  195. elems = append(elems, string(parts[0]), string(parts[1]))
  196. val, err := strconv.Atoi(string(parts[2]))
  197. if err != nil {
  198. return nil, err
  199. }
  200. elems = append(elems, int64(val))
  201. val2, err := strconv.Atoi(string(parts[3]))
  202. if err != nil {
  203. return nil, err
  204. }
  205. elems = append(elems, int64(val2))
  206. } else {
  207. elems = append(elems, string(parts[0]))
  208. parts = parts[1:]
  209. val, err := strconv.Atoi(string(parts[len(parts)-1]))
  210. if err != nil {
  211. return nil, err
  212. }
  213. val2, err := strconv.Atoi(string(parts[len(parts)-2]))
  214. if err != nil {
  215. return nil, err
  216. }
  217. appKey := bytes.Join(parts[:len(parts)-3], []byte("/"))
  218. elems = append(elems, string(appKey), int64(val), int64(val2))
  219. }
  220. return orderedcode.Append(nil, elems...)
  221. case keyIsHash(key):
  222. return orderedcode.Append(nil, "tx.hash", string(key))
  223. default:
  224. return nil, fmt.Errorf("key %q is in the wrong format", string(key))
  225. }
  226. }
  227. func convertEvidence(key keyID, newPrefix int64) ([]byte, error) {
  228. parts := bytes.Split(key[1:], []byte("/"))
  229. if len(parts) != 2 {
  230. return nil, fmt.Errorf("evidence key is malformed with %d parts not 2",
  231. len(parts))
  232. }
  233. hb, err := hex.DecodeString(string(parts[0]))
  234. if err != nil {
  235. return nil, err
  236. }
  237. evidenceHash, err := hex.DecodeString(string(parts[1]))
  238. if err != nil {
  239. return nil, err
  240. }
  241. return orderedcode.Append(nil, newPrefix, binary.BigEndian.Uint64(hb), string(evidenceHash))
  242. }
  243. func replaceKey(db dbm.DB, key keyID, gooseFn migrateFunc) error {
  244. exists, err := db.Has(key)
  245. if err != nil {
  246. return err
  247. }
  248. if !exists {
  249. return nil
  250. }
  251. newKey, err := gooseFn(key)
  252. if err != nil {
  253. return err
  254. }
  255. val, err := db.Get(key)
  256. if err != nil {
  257. return err
  258. }
  259. batch := db.NewBatch()
  260. if err = batch.Set(newKey, val); err != nil {
  261. return err
  262. }
  263. if err = batch.Delete(key); err != nil {
  264. return err
  265. }
  266. // 10% of the time, force a write to disk, but mostly don't,
  267. // because it's faster.
  268. if rand.Intn(100)%10 == 0 { // nolint:gosec
  269. if err = batch.WriteSync(); err != nil {
  270. return err
  271. }
  272. } else {
  273. if err = batch.Write(); err != nil {
  274. return err
  275. }
  276. }
  277. if err = batch.Close(); err != nil {
  278. return err
  279. }
  280. return nil
  281. }
  282. // Migrate converts all legacy key formats to new key formats. The
  283. // operation is idempotent, so it's safe to resume a failed
  284. // operation. The operation is somewhat parallelized, relying on the
  285. // concurrency safety of the underlying databases.
  286. //
  287. // Migrate has "continue on error" semantics and will iterate through
  288. // all legacy keys attempt to migrate them, and will collect all
  289. // errors and will return only at the end of the operation.
  290. //
  291. // The context allows for a safe termination of the operation
  292. // (e.g connected to a singal handler,) to abort the operation
  293. // in-between migration operations.
  294. func Migrate(ctx context.Context, db dbm.DB) error {
  295. keys, err := getAllLegacyKeys(db)
  296. if err != nil {
  297. return err
  298. }
  299. numWorkers := runtime.NumCPU()
  300. wg := &sync.WaitGroup{}
  301. errs := make(chan error, numWorkers)
  302. keyCh := makeKeyChan(keys)
  303. // run migrations.
  304. for i := 0; i < numWorkers; i++ {
  305. wg.Add(1)
  306. go func() {
  307. defer wg.Done()
  308. for key := range keyCh {
  309. err := replaceKey(db, key, migarateKey)
  310. if err != nil {
  311. errs <- err
  312. }
  313. if ctx.Err() != nil {
  314. return
  315. }
  316. }
  317. }()
  318. }
  319. // collect and process the errors.
  320. errStrs := []string{}
  321. signal := make(chan struct{})
  322. go func() {
  323. defer close(signal)
  324. for err := range errs {
  325. if err == nil {
  326. continue
  327. }
  328. errStrs = append(errStrs, err.Error())
  329. }
  330. }()
  331. // Wait for everything to be done.
  332. wg.Wait()
  333. close(errs)
  334. <-signal
  335. // check the error results
  336. if len(errs) != 0 {
  337. return fmt.Errorf("encountered errors during migration: %v", errStrs)
  338. }
  339. return nil
  340. }