Skip to content
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

Use StorageKey for prefixes [ECR-831] #531

Merged

Conversation

vitvakatu
Copy link
Contributor

@vitvakatu vitvakatu commented Mar 1, 2018

  • Removed gen_prefix function
  • Changed signature of with_prefix method

UPDATED

  • Replaced with_prefix with new_in_family.

TODO:

  • Add changelog entry

@vitvakatu vitvakatu added the breaking change ⚠️ API or ABI is changed. label Mar 1, 2018
@vitvakatu vitvakatu force-pushed the ecr_831_use_storagekey_for_prefixes branch 4 times, most recently from d46dace to fc145e1 Compare March 2, 2018 10:50
@vitvakatu
Copy link
Contributor Author

Yay, finally it builds

slowli
slowli previously approved these changes Mar 2, 2018
Copy link
Contributor

@slowli slowli left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks pretty good as of fc145e1.

I wonder if it could make sense to refactor index creation to something like

let x = BaseIndex::new(&snapshot).downcast::<MapIndex<_, K, V>>()?;

That is:

  • Hide all non-BaseIndex constructors
  • (Optional) Hide the BaseIndex constructor too, instead implementing something like snapshot.index("foo") and fork.index_mut(("bar", &public_key)) (both would return BaseIndex).
  • Introduce downcasting to indexes that can fail (and will according to Implement runtime index type checks [ECR-705] #525).

Some description for the second step: introduce a trait

enum IndexLocation {
    Name(String),
    PrefixedName(String, Vec<u8>),
}

impl<'a, S: 'a + AsRef<str>> From<&'a S> for IndexLocation { /* ... */ }
// lifetimes omitted for brevity
impl<S: AsRef<str>, K: StorageKey> From<(&S, &K)> for IndexLocation { /* ... */ }

trait IndexBag<S: AsRef<Snapshot>> {
    fn snapshot(&self) -> S;

    fn index<L, K, V>(&self, location: L) -> Option<BaseIndex<S, K, V>>
    where
        L: Into<IndexLocation>,
        K: StorageKey,
        V: StorageValue
    { /* checks go here */ }

   // Maybe, some other methods
}

// This may be be temporary impl: the checks may be not confined to
// the snapshot, but to more wide context as well (e.g., the service
// requesting access to the storage)
impl<'a> IndexBag<&'a Snapshot> for &'a Snapshot {
    fn snapshot(&self) -> &'a Snapshot { self }
}

Analogous trait can be implemented for mutable indexes:

trait IndexBagMut: IndexBag {
    fn fork(&mut self) -> &mut Fork;
    fn index_mut(&mut self, ...) { /* ... */ }
}

@@ -537,7 +537,7 @@ mod tests {
let path = dir.path();
let db = create_database(path);
let mut fork = db.fork();
let mut list_index = ListIndex::with_prefix(IDX_NAME, vec![01], &mut fork);
let mut list_index = ListIndex::with_prefix(IDX_NAME, &vec![01], &mut fork);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A side note: maybe, it would sense to generate (with macros) StorageKey for [u8; $size] with reasonably small $sizes?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think no, as user will expect that static arrays are working and we'll get a lot of questions like "I've created array of 33 elements but can't use it, what's going on?". I'm looking forward for const expressions in generics.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see it any different from the standard library, which too has "privileged" array types. But I won't insist, ofc.

aleksuss
aleksuss previously approved these changes Mar 2, 2018
Copy link
Contributor

@dmitry-timofeev dmitry-timofeev left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's great to see a PoC, but I don't think we can and should merge it into master as is, because there is a discussion about the idea we want to convey with prefixes and the requirements. Until these things are perfectly clear to everyone, we must not proceed with either design or implementation.

On top of that, by making the existing prefix a StorageKey, the existing thing becomes even more dangerous! Currently it's quite a low-level thing: a byte array. This PR makes it any object that has a StorageKey implementation, creating a false impression that the framework handles any prefixes produced by the serialization code. That's a lie!

Please join the discussion, there are open questions: https://wiki.bf.local/display/EXN/2018-02-27+Meeting+Notes%3A+Friendly+Prefixes

@vitvakatu vitvakatu changed the title Use StorageKey for prefixes [ECR-831] [DO NOT MERGE] Use StorageKey for prefixes [ECR-831] Mar 2, 2018
@slowli
Copy link
Contributor

slowli commented Mar 2, 2018

@dmitry-timofeev As I see it, this API (and creation of indexes in general, for that matter) is low-level plumbing that should be visible / useful for core devs, not service devs. That is, whether this is merged or not, the entire approach with service devs exposed to prefixes is still suboptimal and should be improved.

@vitvakatu
Copy link
Contributor Author

Anyway, I'm waiting for @DarkEld3r decision.

@dmitry-timofeev
Copy link
Contributor

is low-level plumbing that should be visible / useful for core devs

I agree it is low-level, but this PR disguises it as a high-level API, therefore, making it more dangerous. Some serialization code may produce a prefix that is a prefix of another existing prefix!

… not service devs.

That's not entirely true, as we've discovered during the meeting (you must have seen the notes) -- there are valid use-cases when you have to resort to using prefixes to solve a problem at service level.

@stanislav-tkach
Copy link
Contributor

Personally, I don't see a problem in these changes (except for the naming: we should replace "prefix" by something more suitable). As for me, both current and updated APIs require reading the documentation for understanding what this additional parameter is for. Plus we probably preserve API in this state for some time, only prefixes collisions should be fixed, but that is an implementation detail.

@stanislav-tkach
Copy link
Contributor

As for the naming, I'm thinking of something like that:

IndexType::new<S: AsRef<str>>(index_name: S);
IndexType::new_in_family<S: AsRef<str>, I: StorageKey>(family_name: S, index_id: I);

And one more thing: we should prevent the creation of different indexes with the same index_id, just as we do for index names.

- Removed `gen_prefix` function
- Changed signature of `with_prefix` method
@vitvakatu vitvakatu dismissed stale reviews from aleksuss and slowli via bdc3d93 March 12, 2018 07:11
@vitvakatu vitvakatu force-pushed the ecr_831_use_storagekey_for_prefixes branch from fc145e1 to bdc3d93 Compare March 12, 2018 07:11
@vitvakatu vitvakatu changed the title [DO NOT MERGE] Use StorageKey for prefixes [ECR-831] [WIP] Use StorageKey for prefixes [ECR-831] Mar 12, 2018
@vitvakatu vitvakatu force-pushed the ecr_831_use_storagekey_for_prefixes branch from bdc3d93 to bdace90 Compare March 12, 2018 07:17
`with_prefix` renamed into `new_in_family`
@vitvakatu
Copy link
Contributor Author

@DarkEld3r it's not obvious for me why we should check index_id for uniqueness. It's absolutely normal to create several indexes with different family names, but same index ids. It's impossible to use the same index id on the different storage type, because we check storage type while creating family.

@vitvakatu vitvakatu changed the title [WIP] Use StorageKey for prefixes [ECR-831] Use StorageKey for prefixes [ECR-831] Mar 12, 2018
@vitvakatu vitvakatu force-pushed the ecr_831_use_storagekey_for_prefixes branch from 1fc673d to 078016f Compare March 12, 2018 09:07
@stanislav-tkach
Copy link
Contributor

@vitvakatu You are right, but still there is a case which we should prevent: user shouldn't be able to create an index (even with the same type) with "prefix" if a non-prefixed index with the same name already exists (or otherwise).

#[test]
#[should_panic(expected = "Attempt to access an ordinary index 'test_index' \
while it's index family")]
fn invalid_index_type_in_family2() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test should be renamed. 🙃

It can be named index_in_family_as_ordinary_index and the previous test can be named ordinary_index_as_index_in_family.

@stanislav-tkach stanislav-tkach dismissed dmitry-timofeev’s stale review March 13, 2018 14:54

Discussed: will be fixed as separate task

@stanislav-tkach stanislav-tkach merged commit dd9a98a into exonum:master Mar 13, 2018
pavel-mukhanov pushed a commit to pavel-mukhanov/exonum that referenced this pull request Apr 5, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
breaking change ⚠️ API or ABI is changed.
Development

Successfully merging this pull request may close these issues.

5 participants