2

I'm trying to do a simple extension to the comments example by creating a REST API and committing the post to the database. I'm creating the connection outside the scope of the handler itself which I'm assuming is where my problem lies. I'm just not sure how to fix it.

This is the code for the post handler:

server.get("/comments", middleware! {
    let mut stmt = conn.prepare("SELECT * FROM comment").unwrap();
    let mut iter = stmt.query_map(&[], |row| {
        Comment { id: row.get(0), author: row.get(1), text: row.get(2) }
    }).unwrap();

    let mut out: Vec<Comment> = Vec::new();
    for comment in iter {
        out.push(comment.unwrap());
    }

    json::encode(&out).unwrap() 
});

This is the error I get:

<nickel macros>:22:50: 22:66 error: the trait `core::marker::Sync` is not implemented for the type `core::cell::UnsafeCell<rusqlite::InnerConnection>` [E0277]

I assume the error is because I have created the instance and then tried to use it in a closure and that variable is probably destroyed once my main function completes.

tshepang
  • 12,111
  • 21
  • 91
  • 136
Mike Nishizawa
  • 1,410
  • 1
  • 14
  • 14
  • Do you understand what the error message is and means, and just need help overcoming it? – Shepmaster Apr 18 '16 at 13:14
  • Side note, you don't need to specify the type of the vector; `let mut out = Vec::new()` is enough. Even better: `let out: Vec<_> = iter.map(|comment| comment.unwrap()).collect()` – Shepmaster Apr 18 '16 at 13:20
  • I need help overcoming it. I think I understand why it is doing it. I'm assuming it's because I have created the instance and then tried to use it in a closure and that variable is probably destroyed once my main function completes. I'm really trying to just store some data to test the round trip. In Java I might have created a static Map or some other data structure to just hold the data, I don't really need a database. But I couldn't figure out how to do the other so I thought I would try a simple in memory database. – Mike Nishizawa Apr 18 '16 at 16:36

1 Answers1

2

Here's an MCVE that reproduces the problem (you should provide these when asking questions):

extern crate rusqlite;
#[macro_use]
extern crate nickel;

use nickel::{Nickel, HttpRouter};
use rusqlite::Connection;

fn main() {
    let mut server = Nickel::new();
    let conn = Connection::open_in_memory().unwrap();

    server.get("/comments", middleware! {
        let _stmt = conn.prepare("SELECT * FROM comment").unwrap();
        ""
    });

    server.listen("127.0.0.1:6767");
}

The Sync trait says:

Types that are not Sync are those that have "interior mutability" in a non-thread-safe way, such as Cell and RefCell

Which matches with the error message you get. Something inside the Connection has interior mutability which means that the compiler cannot automatically guarantee that sharing it across threads is safe. I had a recent question that might be useful to the implementor of Connection, if they can guarantee it's safe to share (perhaps SQLite itself makes guarantees).

The simplest thing you can do is to ensure that only one thread has access to the database object at a time:

use std::sync::Mutex;

fn main() {
    let mut server = Nickel::new();
    let conn = Mutex::new(Connection::open_in_memory().unwrap());

    server.get("/comments", middleware! {
        let conn = conn.lock().unwrap();
        let _stmt = conn.prepare("SELECT * FROM comment").unwrap();
        ""
    });

    server.listen("127.0.0.1:6767");
}
Community
  • 1
  • 1
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366