Merge commit '347145b4f1c40409c68af0ad61be15ee5f9d04f2' into al-os

This commit is contained in:
Ari Lazier 2015-10-26 12:52:20 -07:00
commit 31819a5ee6
7 changed files with 96 additions and 3 deletions

View File

@ -30,6 +30,7 @@
#include <sstream> #include <sstream>
using namespace realm; using namespace realm;
using namespace realm::_impl;
namespace { namespace {
// Write a byte to a pipe to notify anyone waiting for data on the pipe // Write a byte to a pipe to notify anyone waiting for data on the pipe

View File

@ -26,6 +26,7 @@
namespace realm { namespace realm {
class Realm; class Realm;
namespace _impl {
class ExternalCommitHelper { class ExternalCommitHelper {
public: public:
ExternalCommitHelper(Realm* realm); ExternalCommitHelper(Realm* realm);
@ -87,6 +88,7 @@ private:
FdHolder m_shutdown_write_fd; FdHolder m_shutdown_write_fd;
}; };
} // namespace _impl
} // namespace realm } // namespace realm
#endif /* REALM_EXTERNAL_COMMIT_HELPER_HPP */ #endif /* REALM_EXTERNAL_COMMIT_HELPER_HPP */

View File

@ -316,6 +316,7 @@ public:
} // anonymous namespace } // anonymous namespace
namespace realm { namespace realm {
namespace _impl {
namespace transaction { namespace transaction {
void advance(SharedGroup& sg, ClientHistory& history, RealmDelegate* delegate) { void advance(SharedGroup& sg, ClientHistory& history, RealmDelegate* delegate) {
TransactLogHandler(delegate, sg, [&](auto&&... args) { TransactLogHandler(delegate, sg, [&](auto&&... args) {
@ -344,4 +345,5 @@ void cancel(SharedGroup& sg, ClientHistory& history, RealmDelegate* delegate) {
} }
} // namespace transaction } // namespace transaction
} // namespace _impl
} // namespace realm } // namespace realm

View File

@ -24,6 +24,7 @@ class RealmDelegate;
class SharedGroup; class SharedGroup;
class ClientHistory; class ClientHistory;
namespace _impl {
namespace transaction { namespace transaction {
// Advance the read transaction version, with change notifications sent to delegate // Advance the read transaction version, with change notifications sent to delegate
// Must not be called from within a write transaction. // Must not be called from within a write transaction.
@ -41,6 +42,7 @@ void commit(SharedGroup& sg, ClientHistory& history, RealmDelegate* delegate);
// for reverting to the old values sent to delegate // for reverting to the old values sent to delegate
void cancel(SharedGroup& sg, ClientHistory& history, RealmDelegate* delegate); void cancel(SharedGroup& sg, ClientHistory& history, RealmDelegate* delegate);
} // namespace transaction } // namespace transaction
} // namespace _impl
} // namespace realm } // namespace realm
#endif /* REALM_TRANSACT_LOG_HANDLER_HPP */ #endif /* REALM_TRANSACT_LOG_HANDLER_HPP */

View File

@ -149,6 +149,13 @@ static inline bool property_has_changed(Property const& p1, Property const& p2)
|| p1.is_nullable != p2.is_nullable; || p1.is_nullable != p2.is_nullable;
} }
static inline bool property_can_be_migrated_to_nullable(const Property& old_property, const Property& new_property) {
return old_property.type == new_property.type
&& !old_property.is_nullable
&& new_property.is_nullable
&& new_property.name == old_property.name;
}
void ObjectStore::verify_schema(Schema const& actual_schema, Schema& target_schema, bool allow_missing_tables) { void ObjectStore::verify_schema(Schema const& actual_schema, Schema& target_schema, bool allow_missing_tables) {
std::vector<ObjectSchemaValidationException> errors; std::vector<ObjectSchemaValidationException> errors;
for (auto &object_schema : target_schema) { for (auto &object_schema : target_schema) {
@ -205,6 +212,45 @@ std::vector<ObjectSchemaValidationException> ObjectStore::verify_object_schema(O
return exceptions; return exceptions;
} }
template <typename T>
static void copy_property_values(const Property& old_property, const Property& new_property, Table& table,
T (Table::*getter)(std::size_t, std::size_t) const noexcept,
void (Table::*setter)(std::size_t, std::size_t, T)) {
size_t old_column = old_property.table_column, new_column = new_property.table_column;
size_t count = table.size();
for (size_t i = 0; i < count; i++) {
(table.*setter)(new_column, i, (table.*getter)(old_column, i));
}
}
static void copy_property_values(const Property& source, const Property& destination, Table& table) {
switch (destination.type) {
case PropertyTypeInt:
copy_property_values(source, destination, table, &Table::get_int, &Table::set_int);
break;
case PropertyTypeBool:
copy_property_values(source, destination, table, &Table::get_bool, &Table::set_bool);
break;
case PropertyTypeFloat:
copy_property_values(source, destination, table, &Table::get_float, &Table::set_float);
break;
case PropertyTypeDouble:
copy_property_values(source, destination, table, &Table::get_double, &Table::set_double);
break;
case PropertyTypeString:
copy_property_values(source, destination, table, &Table::get_string, &Table::set_string);
break;
case PropertyTypeData:
copy_property_values(source, destination, table, &Table::get_binary, &Table::set_binary);
break;
case PropertyTypeDate:
copy_property_values(source, destination, table, &Table::get_datetime, &Table::set_datetime);
break;
default:
break;
}
}
// set references to tables on targetSchema and create/update any missing or out-of-date tables // set references to tables on targetSchema and create/update any missing or out-of-date tables
// if update existing is true, updates existing tables, otherwise validates existing tables // if update existing is true, updates existing tables, otherwise validates existing tables
// NOTE: must be called from within write transaction // NOTE: must be called from within write transaction
@ -230,13 +276,40 @@ bool ObjectStore::create_tables(Group *group, Schema &target_schema, bool update
ObjectSchema current_schema(group, target_object_schema->name); ObjectSchema current_schema(group, target_object_schema->name);
std::vector<Property> &target_props = target_object_schema->properties; std::vector<Property> &target_props = target_object_schema->properties;
// handle columns changing from required to optional
for (auto& current_prop : current_schema.properties) {
auto target_prop = target_object_schema->property_for_name(current_prop.name);
if (!target_prop || !property_can_be_migrated_to_nullable(current_prop, *target_prop))
continue;
target_prop->table_column = current_prop.table_column;
current_prop.table_column = current_prop.table_column + 1;
table->insert_column(target_prop->table_column, DataType(target_prop->type), target_prop->name, target_prop->is_nullable);
copy_property_values(current_prop, *target_prop, *table);
table->remove_column(current_prop.table_column);
current_prop.table_column = target_prop->table_column;
changed = true;
}
bool inserted_placeholder_column = false;
// remove extra columns // remove extra columns
size_t deleted = 0; size_t deleted = 0;
for (auto& current_prop : current_schema.properties) { for (auto& current_prop : current_schema.properties) {
current_prop.table_column -= deleted; current_prop.table_column -= deleted;
auto target_prop = target_object_schema->property_for_name(current_prop.name); auto target_prop = target_object_schema->property_for_name(current_prop.name);
if (!target_prop || property_has_changed(current_prop, *target_prop)) { if (!target_prop || (property_has_changed(current_prop, *target_prop)
&& !property_can_be_migrated_to_nullable(current_prop, *target_prop))) {
if (deleted == current_schema.properties.size() - 1) {
// We're about to remove the last column from the table. Insert a placeholder column to preserve
// the number of rows in the table for the addition of new columns below.
table->add_column(type_Bool, "placeholder");
inserted_placeholder_column = true;
}
table->remove_column(current_prop.table_column); table->remove_column(current_prop.table_column);
++deleted; ++deleted;
current_prop.table_column = npos; current_prop.table_column = npos;
@ -273,6 +346,15 @@ bool ObjectStore::create_tables(Group *group, Schema &target_schema, bool update
} }
} }
if (inserted_placeholder_column) {
// We inserted a placeholder due to removing all columns from the table. Remove it, and update the indices
// of any columns that we inserted after it.
table->remove_column(0);
for (auto& target_prop : target_props) {
target_prop.table_column--;
}
}
// update table metadata // update table metadata
if (target_object_schema->primary_key.length()) { if (target_object_schema->primary_key.length()) {
// if there is a primary key set, check if it is the same as the old key // if there is a primary key set, check if it is the same as the old key

View File

@ -29,6 +29,7 @@
#include <mutex> #include <mutex>
using namespace realm; using namespace realm;
using namespace realm::_impl;
RealmCache Realm::s_global_cache; RealmCache Realm::s_global_cache;

View File

@ -28,13 +28,16 @@
namespace realm { namespace realm {
class ClientHistory; class ClientHistory;
class ExternalCommitHelper;
class Realm; class Realm;
class RealmCache; class RealmCache;
class RealmDelegate; class RealmDelegate;
typedef std::shared_ptr<Realm> SharedRealm; typedef std::shared_ptr<Realm> SharedRealm;
typedef std::weak_ptr<Realm> WeakRealm; typedef std::weak_ptr<Realm> WeakRealm;
namespace _impl {
class ExternalCommitHelper;
}
class Realm : public std::enable_shared_from_this<Realm> class Realm : public std::enable_shared_from_this<Realm>
{ {
public: public:
@ -115,7 +118,7 @@ namespace realm {
Group *m_group = nullptr; Group *m_group = nullptr;
std::shared_ptr<ExternalCommitHelper> m_notifier; std::shared_ptr<_impl::ExternalCommitHelper> m_notifier;
public: public:
std::unique_ptr<RealmDelegate> m_delegate; std::unique_ptr<RealmDelegate> m_delegate;