Use major/minor versions for IndexFile

Fixes #364
This commit is contained in:
Fangrui Song 2018-01-27 21:47:37 -08:00
parent 5763201838
commit 70bbe6c64c
5 changed files with 35 additions and 39 deletions

View File

@ -54,7 +54,7 @@ struct RealCacheManager : ICacheManager {
return nullptr;
return Deserialize(config_->cacheFormat, path, *file_content,
IndexFile::kCurrentVersion);
IndexFile::kMajorVersion);
}
std::string GetCachePath(const std::string& source_file) {

View File

@ -565,9 +565,8 @@ void OnIndexReference_Function(IndexFile* db,
} // namespace
// static
const int IndexFile::kCurrentVersion = 10;
const uint64_t IndexFile::kMessagePackMagic = 0x637175657279; // "cquery"
const int IndexFile::kMessagePackVersion = 0;
const int IndexFile::kMajorVersion = 10;
const int IndexFile::kMinorVersion = 0;
IndexFile::IndexFile(const std::string& path,
const optional<std::string>& contents)

View File

@ -483,14 +483,13 @@ MAKE_REFLECT_TYPE_PROXY(LanguageId, std::underlying_type<LanguageId>::type);
struct IndexFile {
IdCache id_cache;
static const int kCurrentVersion;
static const uint64_t kMessagePackMagic;
// MessagePack cache files have its own version number.
// For both JSON and MessagePack cache files.
static const int kMajorVersion;
// For MessagePack cache files.
// 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;
static const int kMinorVersion;
std::string path;
std::vector<std::string> args;

View File

@ -206,7 +206,6 @@ bool ReflectMemberStart(Writer& visitor, IndexFile& value) {
assert(value.Resolve(it->second)->uses.size() == 0);
}
value.version = IndexFile::kCurrentVersion;
DefaultReflectMemberStart(visitor);
return true;
}
@ -214,7 +213,6 @@ template <typename TVisitor>
void Reflect(TVisitor& visitor, IndexFile& value) {
REFLECT_MEMBER_START();
if (!gTestOutputMode) {
REFLECT_MEMBER(version);
REFLECT_MEMBER(last_modification_time);
REFLECT_MEMBER(language);
REFLECT_MEMBER(import_file);
@ -263,6 +261,12 @@ std::string Serialize(SerializeFormat format, IndexFile& file) {
rapidjson::PrettyFormatOptions::kFormatSingleLineArray);
writer.SetIndent(' ', 2);
JsonWriter json_writer(&writer);
if (!gTestOutputMode) {
std::string version = std::to_string(IndexFile::kMajorVersion);
for (char c : version)
output.Put(c);
output.Put('\n');
}
Reflect(json_writer, file);
return output.GetString();
}
@ -270,8 +274,8 @@ std::string Serialize(SerializeFormat format, IndexFile& file) {
msgpack::sbuffer buf;
msgpack::packer<msgpack::sbuffer> pk(&buf);
MessagePackWriter msgpack_writer(&pk);
uint64_t magic = IndexFile::kMessagePackMagic;
int version = IndexFile::kMessagePackVersion;
uint64_t magic = IndexFile::kMajorVersion;
int version = IndexFile::kMinorVersion;
Reflect(msgpack_writer, magic);
Reflect(msgpack_writer, version);
Reflect(msgpack_writer, file);
@ -282,27 +286,26 @@ std::string Serialize(SerializeFormat format, IndexFile& file) {
}
std::unique_ptr<IndexFile> Deserialize(SerializeFormat format,
std::string path,
std::string serialized,
const std::string& path,
const std::string& serialized,
optional<int> expected_version) {
std::unique_ptr<IndexFile> file;
switch (format) {
case SerializeFormat::Json: {
rapidjson::Document reader;
reader.Parse(serialized.c_str());
if (gTestOutputMode)
reader.Parse(serialized.c_str());
else {
const char* p = strchr(serialized.c_str(), '\n');
if (!p)
return nullptr;
if (expected_version && atoi(serialized.c_str()) != *expected_version)
return nullptr;
reader.Parse(p + 1);
}
if (reader.HasParseError())
return nullptr;
// Do not deserialize a document with a bad version. Doing so could cause
// a crash because the file format may have changed.
if (expected_version) {
auto actual_version = reader.FindMember("version");
if (actual_version == reader.MemberEnd() ||
actual_version->value.GetInt() != expected_version) {
return nullptr;
}
}
file = MakeUnique<IndexFile>(path, nullopt);
JsonReader json_reader{&reader};
try {
@ -320,8 +323,7 @@ std::unique_ptr<IndexFile> Deserialize(SerializeFormat format,
if (serialized.empty())
return nullptr;
try {
uint64_t magic;
int version;
int major, minor;
if (serialized.size() < 8)
throw std::invalid_argument("Invalid");
msgpack::unpacker upk;
@ -330,15 +332,11 @@ std::unique_ptr<IndexFile> Deserialize(SerializeFormat format,
upk.buffer_consumed(serialized.size());
file = MakeUnique<IndexFile>(path, nullopt);
MessagePackReader reader(&upk);
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, major);
Reflect(reader, minor);
if (major != IndexFile::kMajorVersion ||
minor != IndexFile::kMinorVersion)
throw std::invalid_argument("Invalid version");
Reflect(reader, *file);
} catch (std::invalid_argument& e) {
LOG_S(INFO) << "Failed to deserialize msgpack '" << path

View File

@ -344,8 +344,8 @@ void ReflectMember(Reader& visitor, const char* name, T& value) {
std::string Serialize(SerializeFormat format, IndexFile& file);
std::unique_ptr<IndexFile> Deserialize(SerializeFormat format,
std::string path,
std::string serialized,
const std::string& path,
const std::string& serialized,
optional<int> expected_version);
void SetTestOutputMode();