diff --git a/src/indexer.cc b/src/indexer.cc index 312d9e6e..df11bbba 100644 --- a/src/indexer.cc +++ b/src/indexer.cc @@ -565,7 +565,9 @@ void OnIndexReference_Function(IndexFile* db, } // namespace // static -int IndexFile::kCurrentVersion = 10; +const int IndexFile::kCurrentVersion = 10; +const uint64_t IndexFile::kMessagePackMagic = 0x6371657279; +const int IndexFile::kMessagePackVersion = 0; IndexFile::IndexFile(const std::string& path, const optional& contents) diff --git a/src/indexer.h b/src/indexer.h index ab3f8581..cd1d6929 100644 --- a/src/indexer.h +++ b/src/indexer.h @@ -479,7 +479,13 @@ MAKE_REFLECT_TYPE_PROXY(LanguageId, std::underlying_type::type); struct IndexFile { IdCache id_cache; - static int kCurrentVersion; + static const int kCurrentVersion; + static const uint64_t kMessagePackMagic; + // MessagePack cache files have its own version number. + // JSON has good forward compatibility because field addition/deletion do not + // harm but currently no efforts have been made to make old MessagePack cache + // files accepted by newer cquery. + static const int kMessagePackVersion; int version = 0; std::string path; diff --git a/src/serializer.cc b/src/serializer.cc index 1c60f40a..e0c485ba 100644 --- a/src/serializer.cc +++ b/src/serializer.cc @@ -271,6 +271,10 @@ std::string Serialize(SerializeFormat format, IndexFile& file) { msgpack::sbuffer buf; msgpack::packer pk(&buf); MessagePackWriter msgpack_writer(&pk); + uint64_t magic = IndexFile::kMessagePackMagic; + int version = IndexFile::kMessagePackVersion; + Reflect(msgpack_writer, magic); + Reflect(msgpack_writer, version); Reflect(msgpack_writer, file); return std::string(buf.data(), buf.size()); } @@ -305,7 +309,7 @@ std::unique_ptr Deserialize(SerializeFormat format, try { Reflect(json_reader, *file); } catch (std::invalid_argument& e) { - LOG_S(ERROR) << "'" << path << "': failed to deserialize " + LOG_S(INFO) << "'" << path << "': failed to deserialize " << json_reader.GetPath() << "." << e.what(); return nullptr; @@ -317,18 +321,29 @@ std::unique_ptr Deserialize(SerializeFormat format, if (serialized.empty()) return nullptr; try { + uint64_t magic; + int version; + if (serialized.size() < 8) + throw std::invalid_argument("Invalid"); msgpack::unpacker upk; upk.reserve_buffer(serialized.size()); memcpy(upk.buffer(), serialized.data(), serialized.size()); upk.buffer_consumed(serialized.size()); file = MakeUnique(path, nullopt); MessagePackReader reader(&upk); - Reflect(reader, *file); - if (file->version != expected_version) + Reflect(reader, magic); + if (magic != IndexFile::kMessagePackMagic) + throw std::invalid_argument("Invalid magic"); + Reflect(reader, version); + if (version != IndexFile::kMessagePackVersion) { + LOG_S(INFO) << "'" << path << "': skip old msgpack version " + << IndexFile::kMessagePackVersion; return nullptr; + } + Reflect(reader, *file); } catch (std::invalid_argument& e) { - LOG_S(ERROR) << "'" << path << "': failed to deserialize msgpack " - << e.what(); + LOG_S(INFO) << "Failed to deserialize msgpack '" << path + << "': " << e.what(); return nullptr; } break;