Thanks to visit codestin.com
Credit goes to github.com

Skip to content

[Enhancement] Path Serialization #228

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 12 commits into from
Dec 2, 2022
120 changes: 9 additions & 111 deletions buildcc/lib/target/include/target/custom_generator.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,38 +39,34 @@ namespace buildcc {

struct UserCustomGeneratorSchema : public internal::CustomGeneratorSchema {
struct UserIdInfo : internal::CustomGeneratorSchema::IdInfo {
fs_unordered_set inputs; // TODO, Remove
GenerateCb generate_cb;
std::shared_ptr<CustomBlobHandler> blob_handler{nullptr};

void ConvertToInternal() {
internal_inputs = internal::path_schema_convert(
inputs, internal::Path::CreateExistingPath);
inputs.ComputeHashForAll();
userblob = blob_handler != nullptr ? blob_handler->GetSerializedData()
: std::vector<uint8_t>();
}
};

using UserIdPair = std::pair<const IdKey, UserIdInfo>;
std::unordered_map<IdKey, UserIdInfo> ids;
GenerateCb generate_cb;
std::shared_ptr<CustomBlobHandler> blob_handler{nullptr};
};

void ConvertToInternal() {
for (auto &[id_key, id_info] : ids) {
id_info.internal_inputs = path_schema_convert(
id_info.inputs, internal::Path::CreateExistingPath);
id_info.ConvertToInternal();
auto [_, success] = internal_ids.try_emplace(id_key, id_info);
env::assert_fatal(success, fmt::format("Could not save {}", id_key));
}
}

std::unordered_map<IdKey, UserIdInfo> ids;
};

class CustomGenerator : public internal::BuilderInterface {
public:
CustomGenerator(const std::string &name, const TargetEnv &env)
: name_(name),
env_(env.GetTargetRootDir(), env.GetTargetBuildDir() / name),
serialization_(env_.GetTargetBuildDir() / fmt::format("{}.json", name)),
comparator_(serialization_.GetLoad(), user_) {
serialization_(env_.GetTargetBuildDir() /
fmt::format("{}.json", name)) {
Initialize();
}
virtual ~CustomGenerator() = default;
Expand Down Expand Up @@ -115,100 +111,9 @@ class CustomGenerator : public internal::BuilderInterface {
const fs::path &GetBuildDir() const { return env_.GetTargetBuildDir(); }
const std::string &Get(const std::string &file_identifier) const;

private:
struct Comparator {
Comparator(const internal::CustomGeneratorSchema &loaded,
const UserCustomGeneratorSchema &us)
: loaded_schema_(loaded), current_schema_(us) {}

enum class State {
kRemoved,
kAdded,
kCheckLater,
};

void AddAllIds() {
const auto &curr_ids = current_schema_.ids;
for (const auto &[id, _] : curr_ids) {
id_state_info_.at(State::kAdded).insert(id);
}
}

void CompareIds() {
const auto &prev_ids = loaded_schema_.internal_ids;
const auto &curr_ids = current_schema_.ids;

for (const auto &[prev_id, _] : prev_ids) {
if (curr_ids.find(prev_id) == curr_ids.end()) {
// Id Removed condition, previous id is not present in the current run
id_state_info_.at(State::kRemoved).insert(prev_id);
}
}

for (const auto &[curr_id, _] : curr_ids) {
if (prev_ids.find(curr_id) == prev_ids.end()) {
// Id Added condition
id_state_info_.at(State::kAdded).insert(curr_id);
} else {
// Id Check Later condition
id_state_info_.at(State::kCheckLater).insert(curr_id);
}
}
}

bool IsChanged(const std::string &id) const {
const auto &previous_id_info = loaded_schema_.internal_ids.at(id);
const auto &current_id_info = current_schema_.ids.at(id);

bool changed = internal::CheckPaths(previous_id_info.internal_inputs,
current_id_info.internal_inputs) !=
internal::PathState::kNoChange;
changed = changed || internal::CheckChanged(previous_id_info.outputs,
current_id_info.outputs);
if (!changed && current_id_info.blob_handler != nullptr) {
// We only check blob handler if not changed by inputs/outputs
// Checking blob_handler could be expensive so this optimization is made
// to run only when changed == false
changed = current_id_info.blob_handler->CheckChanged(
previous_id_info.userblob, current_id_info.userblob);
}
return changed;
}

const std::unordered_set<std::string> &GetRemovedIds() const {
return id_state_info_.at(State::kRemoved);
}

const std::unordered_set<std::string> &GetAddedIds() const {
return id_state_info_.at(State::kAdded);
}

const std::unordered_set<std::string> &GetCheckLaterIds() const {
return id_state_info_.at(State::kCheckLater);
}

bool IsIdAdded(const std::string &id) const {
return id_state_info_.at(State::kAdded).count(id) == 1;
}

private:
const internal::CustomGeneratorSchema &loaded_schema_;
const UserCustomGeneratorSchema &current_schema_;
std::unordered_map<State, std::unordered_set<std::string>> id_state_info_{
{State::kRemoved, std::unordered_set<std::string>()},
{State::kAdded, std::unordered_set<std::string>()},
{State::kCheckLater, std::unordered_set<std::string>()},
};
};

private:
void Initialize();

tf::Task CreateTaskRunner(tf::Subflow &subflow, const std::string &id);
void TaskRunner(const std::string &id);

void GenerateTask();
void BuildGenerate();

// Recheck states
void IdRemoved();
Expand All @@ -227,13 +132,6 @@ class CustomGenerator : public internal::BuilderInterface {
// Serialization
UserCustomGeneratorSchema user_;

// Comparator
Comparator comparator_;

std::mutex success_schema_mutex_;
std::unordered_map<std::string, UserCustomGeneratorSchema::UserIdInfo>
success_schema_;

// Internal
env::Command command_;
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@

namespace buildcc {

/**
* @brief Abstract class for serializing additional data for which rebuilds
* might be triggered i.e data that is not input/output files
* TODO, Add examples here
*
*/
class CustomBlobHandler {
public:
CustomBlobHandler() = default;
Expand Down Expand Up @@ -54,6 +60,48 @@ class CustomBlobHandler {
virtual std::vector<uint8_t> Serialize() const = 0;
};

/**
* @brief Typed Custom Blob handler which automatically performs Serialization
* and Deserialization as long as it is JSON serializable
*
* NOTE: Type data is stored as a reference (to avoid copying large amount of
* data) when constructing TypedCustomBlobHandler
*
* @tparam Type should be JSON serializable (see nlohmann::json compatible
* objects)
*/
template <typename Type>
class TypedCustomBlobHandler : public CustomBlobHandler {
public:
explicit TypedCustomBlobHandler(const Type &data) : data_(data) {}

// serialized_data has already been verified
static Type Deserialize(const std::vector<uint8_t> &serialized_data) {
json j = json::from_msgpack(serialized_data, true, false);
Type deserialized;
j.get_to(deserialized);
return deserialized;
}

private:
const Type &data_;

bool Verify(const std::vector<uint8_t> &serialized_data) const override {
json j = json::from_msgpack(serialized_data, true, false);
return !j.is_discarded();
}

bool IsEqual(const std::vector<uint8_t> &previous,
const std::vector<uint8_t> &current) const override {
return Deserialize(previous) == Deserialize(current);
}

std::vector<uint8_t> Serialize() const override {
json j = data_;
return json::to_msgpack(j);
}
};

} // namespace buildcc

#endif
Original file line number Diff line number Diff line change
Expand Up @@ -25,19 +25,20 @@ namespace buildcc {

class CustomGeneratorContext {
public:
CustomGeneratorContext(const env::Command &c, const fs_unordered_set &i,
const fs_unordered_set &o,
CustomGeneratorContext(const env::Command &c,
const std::unordered_set<std::string> &i,
const std::unordered_set<std::string> &o,
const std::vector<uint8_t> &ub)
: command(c), inputs(i), outputs(o), userblob(ub) {}

const env::Command &command;
const fs_unordered_set &inputs;
const fs_unordered_set &outputs;
const std::unordered_set<std::string> &inputs;
const std::unordered_set<std::string> &outputs;
const std::vector<uint8_t> &userblob;
};

// clang-format off
using GenerateCb = std::function<bool (CustomGeneratorContext &)>;
using GenerateCb = std::function<bool (const CustomGeneratorContext &)>;
// clang-format on

} // namespace buildcc
Expand Down
Loading