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

Tree can not be shared across threads safely #1507

Open
spacekookie opened this issue Jun 13, 2024 · 1 comment
Open

Tree can not be shared across threads safely #1507

spacekookie opened this issue Jun 13, 2024 · 1 comment

Comments

@spacekookie
Copy link
Contributor

spacekookie commented Jun 13, 2024

I've been migrating a project to sled from a different embedded db and I'm getting some strange compilation errors:

error: future cannot be sent between threads safely
   --> ratman/src/journal/page.rs:99:85
    |
99  |       async fn fetch(&self, reference: &BlockReference) -> IoResult<Option<Block<L>>> {
    |  _____________________________________________________________________________________^
100 | |         match self.get(&reference.to_string()) {
101 | |             Err(RatmanError::Io(io)) => Err(io),
102 | |             Ok(Some(BlockData { data, valid })) if valid => Ok(Some(data.to_block())),
103 | |             _ => Ok(None),
104 | |         }
105 | |     }
    | |_____^ future created by async block is not `Send`
    |
    = help: within `Tree`, the trait `Sync` is not implemented for `RefCell<ebr::Inner<concurrent_map::Deferred<sled::ObjectId, sled::Object<1024>, 64>, 128, 128>>`, which is required by `{async block@ratman/src/journal/page.rs:99:85: 105:6}: std::marker::Send`
    = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` instead
note: captured value is not `Send` because `&` references cannot be sent unless their referent is `Sync`

The type this is implemented for is:

pub struct CachePage<T: Serialize + DeserializeOwned>(pub Arc<sled::Tree>, pub PhantomData<T>);

And this is the trait definition that causes problems:

#[async_trait]
impl<const L: usize> BlockStorage<L> for CachePage<BlockData> {
    async fn store(&self, block: &Block<L>) -> IoResult<()> {
        self.insert(
            block.reference().to_string(),
            &BlockData {
                // We can unwrap here because the blocks were previously
                // verified to be valid
                data: StorageBlock::reconstruct(block.as_slice()).unwrap(),
                valid: true,
            },
        )?;
        Ok(())
    }

    async fn fetch(&self, reference: &BlockReference) -> IoResult<Option<Block<L>>> {
        match self.get(&reference.to_string()) {
            Err(RatmanError::Io(io)) => Err(io),
            Ok(Some(BlockData { data, valid })) if valid => Ok(Some(data.to_block())),
            _ => Ok(None),
        }
    }
}

Is this a bug or am I holding the Tree wrong? Oh and I'm using version 1.0.0-alpha.121

@rail-ka
Copy link

rail-ka commented Jun 26, 2024

I am not a Sled developer, but I have encountered a similar problem. The solution was not to share the Tree between threads, but to clone it for each thread.

P.S.
It is also better to wrap Tree in Box, because the size on the stack is 7648 bytes, and there may be a stack overflow error.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants