mirror of
https://github.com/facebook/sapling.git
synced 2024-10-12 01:39:21 +03:00
c12e300bb8
Summary: Move top-level Python packages `mercurial`, `hgext` and `hgdemandimport` to a new top-level package `edenscm`. This allows the Python packages provided by the upstream Mercurial to be installed side-by-side. To maintain compatibility, `edenscm/` gets added to `sys.path` in `mercurial/__init__.py`. Reviewed By: phillco, ikostia Differential Revision: D13853115 fbshipit-source-id: b296b0673dc54c61ef6a591ebc687057ff53b22e
159 lines
4.2 KiB
C++
159 lines
4.2 KiB
C++
// Copyright (c) 2004-present, Facebook, Inc.
|
|
// All Rights Reserved.
|
|
//
|
|
// This software may be used and distributed according to the terms of the
|
|
// GNU General Public License version 2 or any later version.
|
|
|
|
// uniondatapackstore.cpp - implementation of a union datapack store
|
|
// no-check-code
|
|
|
|
#include "edenscm/hgext/extlib/cstore/uniondatapackstore.h"
|
|
#include "edenscm/hgext/extlib/cstore/util.h"
|
|
|
|
#include <algorithm>
|
|
#include <memory>
|
|
|
|
extern "C" {
|
|
#include "edenscm/mercurial/mpatch.h"
|
|
}
|
|
|
|
UnionDatapackStore::UnionDatapackStore() {}
|
|
|
|
UnionDatapackStore::UnionDatapackStore(std::vector<DataStore*>& stores)
|
|
: _stores(stores) {}
|
|
|
|
UnionDatapackStore::~UnionDatapackStore() {
|
|
// TODO: we should manage the substore lifetimes here, but because they are
|
|
// also controlled by Python, we need to let python handle it and manage the
|
|
// refcount in the py_uniondatapackstore type.
|
|
}
|
|
|
|
mpatch_flist* getNextLink(void* container, ssize_t index) {
|
|
std::vector<DeltaChainLink>* links = (std::vector<DeltaChainLink>*)container;
|
|
|
|
if (index < 0 || (size_t)index >= links->size()) {
|
|
return NULL;
|
|
}
|
|
|
|
DeltaChainLink link = links->at(index);
|
|
|
|
struct mpatch_flist* res;
|
|
if ((mpatch_decode(
|
|
(const char*)link.delta(), (ssize_t)link.deltasz(), &res)) < 0) {
|
|
throw std::logic_error("invalid patch during patch application");
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
ConstantStringRef UnionDatapackStore::get(const Key& key) {
|
|
UnionDeltaChainIterator chain = this->getDeltaChain(key);
|
|
|
|
std::vector<DeltaChainLink> links;
|
|
|
|
for (DeltaChainLink link = chain.next(); !link.isdone();
|
|
link = chain.next()) {
|
|
links.push_back(link);
|
|
}
|
|
|
|
DeltaChainLink fulltextLink = links.back();
|
|
links.pop_back();
|
|
|
|
// Short circuit and just return the full text if it's one long
|
|
if (links.size() == 0) {
|
|
return ConstantStringRef(
|
|
(const char*)fulltextLink.delta(), (size_t)fulltextLink.deltasz());
|
|
}
|
|
|
|
std::reverse(links.begin(), links.end());
|
|
|
|
mpatch_flist* patch = mpatch_fold(&links, getNextLink, 0, links.size());
|
|
if (!patch) { /* error already set or memory error */
|
|
throw std::logic_error("mpatch failed to fold patches");
|
|
}
|
|
|
|
ssize_t outlen = mpatch_calcsize((ssize_t)fulltextLink.deltasz(), patch);
|
|
if (outlen < 0) {
|
|
mpatch_lfree(patch);
|
|
throw std::logic_error("mpatch failed to calculate size");
|
|
}
|
|
|
|
auto result = std::make_shared<std::string>(outlen, '\0');
|
|
if (mpatch_apply(
|
|
&(*result)[0],
|
|
(const char*)fulltextLink.delta(),
|
|
(ssize_t)fulltextLink.deltasz(),
|
|
patch) < 0) {
|
|
mpatch_lfree(patch);
|
|
throw std::logic_error("mpatch failed to apply patches");
|
|
}
|
|
|
|
mpatch_lfree(patch);
|
|
return ConstantStringRef(result);
|
|
}
|
|
|
|
std::shared_ptr<DeltaChain> UnionDeltaChainIterator::getNextChain(
|
|
const Key& key) {
|
|
for (std::vector<DataStore*>::iterator it = _store._stores.begin();
|
|
it != _store._stores.end();
|
|
it++) {
|
|
DataStore* substore = *it;
|
|
std::shared_ptr<DeltaChain> chain = substore->getDeltaChainRaw(key);
|
|
|
|
if (chain->status() == GET_DELTA_CHAIN_OK) {
|
|
return chain;
|
|
}
|
|
}
|
|
|
|
throw MissingKeyError("unable to find delta chain");
|
|
}
|
|
|
|
UnionDeltaChainIterator UnionDatapackStore::getDeltaChain(const Key& key) {
|
|
return UnionDeltaChainIterator(*this, key);
|
|
}
|
|
|
|
Key* UnionDatapackStoreKeyIterator::next() {
|
|
Key* key;
|
|
while ((key = _missing.next()) != NULL) {
|
|
if (!_store.contains(*key)) {
|
|
return key;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
bool UnionDatapackStore::contains(const Key& key) {
|
|
for (std::vector<DataStore*>::iterator it = _stores.begin();
|
|
it != _stores.end();
|
|
it++) {
|
|
DataStore* substore = *it;
|
|
if (substore->contains(key)) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
UnionDatapackStoreKeyIterator UnionDatapackStore::getMissing(
|
|
KeyIterator& missing) {
|
|
return UnionDatapackStoreKeyIterator(*this, missing);
|
|
}
|
|
|
|
void UnionDatapackStore::markForRefresh() {
|
|
for (std::vector<DataStore*>::iterator it = _stores.begin();
|
|
it != _stores.end();
|
|
it++) {
|
|
DataStore* substore = *it;
|
|
substore->markForRefresh();
|
|
}
|
|
}
|
|
|
|
void UnionDatapackStore::addStore(DataStore* store) {
|
|
_stores.push_back(store);
|
|
}
|
|
|
|
void UnionDatapackStore::removeStore(DataStore* store) {
|
|
removeFromVector<DataStore*>(_stores, store);
|
|
}
|