Восстановить данные из cockroachdb легко — просто накатите всё из бекапа. Как это не делали бэкапы? Для базы, у которой версия 1.0 вышла всего полгода назад? Что ж, не отчаивайтесь, скорее всего данные можно восстановить. Я буду рассказывать про то, как я восстанавливал базу данных для своего проекта потешной социальной сети вбамбуке и стримил сей процесс на ютьюбе.
E171219 15:50:36.541517 25 util/log/crash_reporting.go:82 a panic has occurred!
E171219 15:50:36.734485 74 util/log/crash_reporting.go:82 a panic has occurred!
E171219 15:50:37.241298 25 util/log/crash_reporting.go:174 Reported as error 20a3dd770da3404fa573411e2b2ffe09
panic: Corruption: block checksum mismatch [recovered]
panic: Corruption: block checksum mismatch
goroutine 25 [running]:
github.com/cockroachdb/cockroach/pkg/util/stop.(*Stopper).Recover(0xc4206c8500, 0x7fb299f4b180, 0xc4209de120)
/go/src/github.com/cockroachdb/cockroach/pkg/util/stop/stopper.go:200 +0xb1
panic(0x1957a00, 0xc4240398a0)
/usr/local/go/src/runtime/panic.go:489 +0x2cf
github.com/cockroachdb/cockroach/pkg/storage.(*Store).processReady(0xc420223000, 0x103)
/go/src/github.com/cockroachdb/cockroach/pkg/storage/store.go:3411 +0x427
$ cockroach debug rocksdb repair
E171219 13:12:47.618517 1 cli/error.go:68 cockroach server exited with error: cannot verify empty engine for bootstrap: unable to read store ident: store has not been bootstrapped
Error: cockroach server exited with error: cannot verify empty engine for bootstrap: unable to read store ident: store has not been bootstrapped
cockroach_comparator
. Я взял нужный компаратор из исходников самого cockroach, но ничего не поменялось.package main
import "github.com/cockroachdb/cockroach/pkg/storage/engine"
func main() {
db, err := engine.NewRocksDB(engine.RocksDBConfig{
Dir: "/Users/yuriy/tmp/vbambuke",
MustExist: true,
}, engine.NewRocksDBCache(1000000))
if err != nil {
log.Fatalf("Could not open cockroach rocksdb: %v", err.Error())
}
db.Iterate(
engine.MVCCKey{Timestamp: hlc.MinTimestamp},
engine.MVCCKeyMax,
func(kv engine.MVCCKeyValue) (bool, error) {
if bytes.Contains([]byte(kv.Value), []byte("safari@apple.com")) {
log.Printf("Email key: %s", kv.Key)
}
return false, nil
},
)
}
Email key: /Table/54/1/158473728194052097/0/1503250869.243064075,0
CREATE TABLE messages (
id SERIAL PRIMARY KEY,
user_id BIGINT,
user_id_to BIGINT,
is_out BOOL,
message TEXT,
ts BIGINT
);
$ head -n 2 messages | od -c
0000000 1 / 1 / 0 / 1 5 0 3 2 5 0 8 6 8
0000020 . 7 2 7 5 5 4 8 2 8 , 0
0000040 = 241 E 270 276 \n # 202 200 230 316
0000060 316 ? ** 263 004 023 202 200 204 231 374 235 222 264 004 032
0000100 026 031 N o w I u s e r e a l
0000120 P o s t g r e S Q L 023 230 277 256 217
0000140 240 320 375 342 ( \n
0000146
0000000 1 / 1 / 0 / 1 5 0 3 2 5 0 8 6 8
0000020 . 7 2 7 5 5 4 8 2 8 , 0
0000040 =
241 E 270 276 \n #
он всегда разный, но для всех моих таблиц первые 6 байт нужно было просто пропустить.0000040 = 241 E 270 276 \n # отсюда ---> 202 200 230 316
0000060 316 ? ** 263 004 <---- досюда 023 202 200 204 231 374 235 222 264 004 032
func readVarIntFirst(v []byte) ([]byte, int64) {
res, ln := binary.Varint(v)
if ln <= 0 {
panic("could not read varint")
}
return v[ln:], res
}
func readVarInt(v []byte) ([]byte, int64) {
if v[0] != '\023' {
panic("invalid varint prefix")
}
return readVarIntFirst(v[1:])
}
github.com/cockroachdb/cockroach/pkg/util/encoding
под названием encoding.DecodeBoolValue Эта функция работает примерно также, как и объявленные выше, только возвращает ошибку вместо паники. Мы используем panic для удобства — нам в одноразовой утилите ошибки шибко по-умному обрабатывать не надо.0000100 026 031 N o w I u s e r e a l
0000120 P o s t g r e S Q L 023 230 277 256 217
0000140 240 320 375 342 ( \n
func readStringFirst(v []byte) ([]byte, string) {
v, _, ln, err := encoding.DecodeNonsortingUvarint(v)
if err != nil {
panic("could not decode string length")
}
return v[ln:], string(v[0:ln])
}
func readString(v []byte) ([]byte, string) {
if v[0] != '\026' {
panic("invalid string prefix")
}
return readStringFirst(v[1:])
}
v, birthdate := readVarInt(v)
ts := time.Unix(birthdate*86400, 0)
formatted := fmt.Sprintf("%04d-%02d-%02d", ts.Year(), ts.Month(), ts.Day())
func escape(q string) string {
var b bytes.Buffer
for _, c := range q {
b.WriteRune(c)
if c == '\'' {
b.WriteRune(c)
}
}
return b.String()
}
fmt.Printf(
"INSERT INTO messages2(id, user_id, user_id_to, is_out, message, ts) VALUES(%s, %d, %d, %v, '%s', %d);\n",
pk, userID, userIDTo, isOut, escape(message), ts,
)
К сожалению, не доступен сервер mySQL