|
|
@ -10,12 +10,13 @@ |
|
|
|
)] |
|
|
|
)] |
|
|
|
|
|
|
|
|
|
|
|
use clap::{Parser, Subcommand}; |
|
|
|
use clap::{Parser, Subcommand}; |
|
|
|
|
|
|
|
use flate2::read::MultiGzDecoder; |
|
|
|
use oxhttp::model::{Body, HeaderName, HeaderValue, Request, Response, Status}; |
|
|
|
use oxhttp::model::{Body, HeaderName, HeaderValue, Request, Response, Status}; |
|
|
|
use oxhttp::Server; |
|
|
|
use oxhttp::Server; |
|
|
|
use oxigraph::io::{DatasetFormat, DatasetSerializer, GraphFormat, GraphSerializer}; |
|
|
|
use oxigraph::io::{DatasetFormat, DatasetSerializer, GraphFormat, GraphSerializer}; |
|
|
|
use oxigraph::model::{GraphName, GraphNameRef, IriParseError, NamedNode, NamedOrBlankNode}; |
|
|
|
use oxigraph::model::{GraphName, GraphNameRef, IriParseError, NamedNode, NamedOrBlankNode}; |
|
|
|
use oxigraph::sparql::{Query, QueryResults, Update}; |
|
|
|
use oxigraph::sparql::{Query, QueryResults, Update}; |
|
|
|
use oxigraph::store::Store; |
|
|
|
use oxigraph::store::{BulkLoader, Store}; |
|
|
|
use oxiri::Iri; |
|
|
|
use oxiri::Iri; |
|
|
|
use rand::random; |
|
|
|
use rand::random; |
|
|
|
use sparesults::{QueryResultsFormat, QueryResultsSerializer}; |
|
|
|
use sparesults::{QueryResultsFormat, QueryResultsSerializer}; |
|
|
@ -76,7 +77,9 @@ pub fn main() -> std::io::Result<()> { |
|
|
|
|
|
|
|
|
|
|
|
match matches.command { |
|
|
|
match matches.command { |
|
|
|
Command::Load { file } => { |
|
|
|
Command::Load { file } => { |
|
|
|
let handles = file.iter().map(|file| { |
|
|
|
let handles = file |
|
|
|
|
|
|
|
.iter() |
|
|
|
|
|
|
|
.map(|file| { |
|
|
|
let store = store.clone(); |
|
|
|
let store = store.clone(); |
|
|
|
let file = file.to_string(); |
|
|
|
let file = file.to_string(); |
|
|
|
spawn(move || { |
|
|
|
spawn(move || { |
|
|
@ -84,27 +87,26 @@ pub fn main() -> std::io::Result<()> { |
|
|
|
let start = Instant::now(); |
|
|
|
let start = Instant::now(); |
|
|
|
let loader = store.bulk_loader().on_progress(move |size| { |
|
|
|
let loader = store.bulk_loader().on_progress(move |size| { |
|
|
|
let elapsed = start.elapsed(); |
|
|
|
let elapsed = start.elapsed(); |
|
|
|
println!("{} triples loaded in {}s ({} t/s) from {}", size, elapsed.as_secs(), size / elapsed.as_secs(), f) |
|
|
|
println!( |
|
|
|
|
|
|
|
"{} triples loaded in {}s ({} t/s) from {}", |
|
|
|
|
|
|
|
size, |
|
|
|
|
|
|
|
elapsed.as_secs(), |
|
|
|
|
|
|
|
size / elapsed.as_secs(), |
|
|
|
|
|
|
|
f |
|
|
|
|
|
|
|
) |
|
|
|
}); |
|
|
|
}); |
|
|
|
let reader = BufReader::new(File::open(&file)?); |
|
|
|
if file.ends_with(".gz") { |
|
|
|
if let Some(format) = file |
|
|
|
bulk_load( |
|
|
|
.rsplit_once('.') |
|
|
|
loader, |
|
|
|
.and_then(|(_, extension)| DatasetFormat::from_extension(extension)) { |
|
|
|
&file[..file.len() - 3], |
|
|
|
loader.load_dataset(reader, format, None)?; |
|
|
|
MultiGzDecoder::new(File::open(&file)?), |
|
|
|
Ok(()) |
|
|
|
) |
|
|
|
} else if let Some(format) = file |
|
|
|
|
|
|
|
.rsplit_once('.') |
|
|
|
|
|
|
|
.and_then(|(_, extension)| GraphFormat::from_extension(extension)) { |
|
|
|
|
|
|
|
loader.load_graph(reader, format, GraphNameRef::DefaultGraph, None)?; |
|
|
|
|
|
|
|
Ok(()) |
|
|
|
|
|
|
|
} else { |
|
|
|
} else { |
|
|
|
Err(io::Error::new( |
|
|
|
bulk_load(loader, &file, File::open(&file)?) |
|
|
|
ErrorKind::InvalidInput, |
|
|
|
|
|
|
|
"The server is not able to guess the file format of {} from its extension", |
|
|
|
|
|
|
|
)) |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
}) |
|
|
|
}) |
|
|
|
}).collect::<Vec<JoinHandle<io::Result<()>>>>(); |
|
|
|
}) |
|
|
|
|
|
|
|
.collect::<Vec<JoinHandle<io::Result<()>>>>(); |
|
|
|
for handle in handles { |
|
|
|
for handle in handles { |
|
|
|
handle.join().unwrap()?; |
|
|
|
handle.join().unwrap()?; |
|
|
|
} |
|
|
|
} |
|
|
@ -124,6 +126,28 @@ pub fn main() -> std::io::Result<()> { |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn bulk_load(loader: BulkLoader, file: &str, reader: impl Read) -> io::Result<()> { |
|
|
|
|
|
|
|
let (_, extension) = file.rsplit_once('.').ok_or_else(|| io::Error::new( |
|
|
|
|
|
|
|
ErrorKind::InvalidInput, |
|
|
|
|
|
|
|
format!("The server is not able to guess the file format of {} because the file name as no extension", file)))?; |
|
|
|
|
|
|
|
let reader = BufReader::new(reader); |
|
|
|
|
|
|
|
if let Some(format) = DatasetFormat::from_extension(extension) { |
|
|
|
|
|
|
|
loader.load_dataset(reader, format, None)?; |
|
|
|
|
|
|
|
Ok(()) |
|
|
|
|
|
|
|
} else if let Some(format) = GraphFormat::from_extension(extension) { |
|
|
|
|
|
|
|
loader.load_graph(reader, format, GraphNameRef::DefaultGraph, None)?; |
|
|
|
|
|
|
|
Ok(()) |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
Err(io::Error::new( |
|
|
|
|
|
|
|
ErrorKind::InvalidInput, |
|
|
|
|
|
|
|
format!( |
|
|
|
|
|
|
|
"The server is not able to guess the file format from the extension {}", |
|
|
|
|
|
|
|
extension |
|
|
|
|
|
|
|
), |
|
|
|
|
|
|
|
)) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
fn handle_request(request: &mut Request, store: Store) -> Response { |
|
|
|
fn handle_request(request: &mut Request, store: Store) -> Response { |
|
|
|
match (request.url().path(), request.method().as_ref()) { |
|
|
|
match (request.url().path(), request.method().as_ref()) { |
|
|
|
("/", "HEAD") => Response::builder(Status::OK) |
|
|
|
("/", "HEAD") => Response::builder(Status::OK) |
|
|
|