summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorAshley Mannix <ashleymannix@live.com.au>2017-05-28 19:20:10 +1000
committerPaul Masurel <paul.masurel@gmail.com>2017-05-29 18:29:39 +0900
commit1bcebdd29e7366e3b9d3179e2b08775ea4edc880 (patch)
treec39a04082b205d5714889eb289d71ce1f59be9f1 /src
parented0333a404ba300b80d95594ec4132aedfa31116 (diff)
initial error-chain
Diffstat (limited to 'src')
-rw-r--r--src/core/index.rs4
-rw-r--r--src/directory/error.rs59
-rw-r--r--src/directory/managed_directory.rs9
-rw-r--r--src/directory/mmap_directory.rs40
-rw-r--r--src/directory/ram_directory.rs11
-rw-r--r--src/error.rs108
-rw-r--r--src/indexer/index_writer.rs20
-rw-r--r--src/indexer/merger.rs4
-rw-r--r--src/indexer/segment_updater.rs8
-rw-r--r--src/lib.rs3
10 files changed, 171 insertions, 95 deletions
diff --git a/src/core/index.rs b/src/core/index.rs
index e43cfc7..34453ad 100644
--- a/src/core/index.rs
+++ b/src/core/index.rs
@@ -1,5 +1,5 @@
use Result;
-use Error;
+use error::*;
use serde_json;
use schema::Schema;
use std::sync::Arc;
@@ -30,7 +30,7 @@ fn load_metas(directory: &Directory) -> Result<IndexMeta> {
let meta_data = directory.atomic_read(&META_FILEPATH)?;
let meta_string = String::from_utf8_lossy(&meta_data);
serde_json::from_str(&meta_string)
- .map_err(|e| Error::CorruptedFile(META_FILEPATH.clone(), Box::new(e)))
+ .chain_err(|| ErrorKind::CorruptedFile(META_FILEPATH.clone()))
}
/// Tantivy's Search Index
diff --git a/src/directory/error.rs b/src/directory/error.rs
index 2bc2b6f..c3d2ece 100644
--- a/src/directory/error.rs
+++ b/src/directory/error.rs
@@ -1,5 +1,43 @@
use std::path::PathBuf;
use std::io;
+use std::fmt;
+
+/// General IO error with an optional path to the offending file.
+#[derive(Debug)]
+pub struct IOError {
+ path: Option<PathBuf>,
+ err: io::Error,
+}
+
+impl fmt::Display for IOError {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match self.path {
+ Some(ref path) => write!(f, "io error occurred on path '{:?}': '{}'", path, self.err),
+ None => write!(f, "io error occurred: '{}'", self.err),
+ }
+ }
+}
+
+impl IOError {
+ pub(crate) fn with_path(
+ path: PathBuf,
+ err: io::Error)
+ -> Self {
+ IOError {
+ path: Some(path),
+ err: err,
+ }
+ }
+}
+
+impl From<io::Error> for IOError {
+ fn from(err: io::Error) -> IOError {
+ IOError {
+ path: None,
+ err: err,
+ }
+ }
+}
/// Error that may occur when opening a directory
#[derive(Debug)]
@@ -18,11 +56,11 @@ pub enum OpenWriteError {
FileAlreadyExists(PathBuf),
/// Any kind of IO error that happens when
/// writing in the underlying IO device.
- IOError(io::Error),
+ IOError(IOError),
}
-impl From<io::Error> for OpenWriteError {
- fn from(err: io::Error) -> OpenWriteError {
+impl From<IOError> for OpenWriteError {
+ fn from(err: IOError) -> OpenWriteError {
OpenWriteError::IOError(err)
}
}
@@ -34,9 +72,14 @@ pub enum OpenReadError {
FileDoesNotExist(PathBuf),
/// Any kind of IO error that happens when
/// interacting with the underlying IO device.
- IOError(io::Error),
+ IOError(IOError),
}
+impl From<IOError> for OpenReadError {
+ fn from(err: IOError) -> OpenReadError {
+ OpenReadError::IOError(err)
+ }
+}
/// Error that may occur when trying to delete a file
#[derive(Debug)]
@@ -45,8 +88,14 @@ pub enum DeleteError {
FileDoesNotExist(PathBuf),
/// Any kind of IO error that happens when
/// interacting with the underlying IO device.
- IOError(io::Error),
+ IOError(IOError),
/// The file may not be deleted because it is
/// protected.
FileProtected(PathBuf),
}
+
+impl From<IOError> for DeleteError {
+ fn from(err: IOError) -> DeleteError {
+ DeleteError::IOError(err)
+ }
+}
diff --git a/src/directory/managed_directory.rs b/src/directory/managed_directory.rs
index 7b87bdd..e957bd0 100644
--- a/src/directory/managed_directory.rs
+++ b/src/directory/managed_directory.rs
@@ -1,6 +1,6 @@
use std::path::{Path, PathBuf};
use serde_json;
-use directory::error::{OpenReadError, DeleteError, OpenWriteError};
+use directory::error::{IOError, OpenReadError, DeleteError, OpenWriteError};
use directory::{ReadOnlySource, WritePtr};
use std::result;
use std::io;
@@ -12,8 +12,7 @@ use std::io::Write;
use core::MANAGED_FILEPATH;
use std::collections::HashMap;
use std::fmt;
-use Result;
-use Error;
+use error::*;
/// Wrapper of directories that keeps track of files created by Tantivy.
///
@@ -86,7 +85,7 @@ impl ManagedDirectory {
let managed_files_json = String::from_utf8_lossy(&data);
let managed_files: HashSet<PathBuf> =
serde_json::from_str(&managed_files_json)
- .map_err(|e| Error::CorruptedFile(MANAGED_FILEPATH.clone(), Box::new(e)))?;
+ .chain_err(|| ErrorKind::CorruptedFile(MANAGED_FILEPATH.clone()))?;
Ok(ManagedDirectory {
directory: box directory,
meta_informations: Arc::new(RwLock::new(MetaInformation {
@@ -230,7 +229,7 @@ impl Directory for ManagedDirectory {
}
fn open_write(&mut self, path: &Path) -> result::Result<WritePtr, OpenWriteError> {
- self.register_file_as_managed(path)?;
+ self.register_file_as_managed(path).map_err(|e| IOError::with_path(path.to_owned(), e))?;
self.directory.open_write(path)
}
diff --git a/src/directory/mmap_directory.rs b/src/directory/mmap_directory.rs
index f01c813..6e48a00 100644
--- a/src/directory/mmap_directory.rs
+++ b/src/directory/mmap_directory.rs
@@ -1,7 +1,7 @@
use atomicwrites;
use common::make_io_err;
use directory::Directory;
-use directory::error::{OpenWriteError, OpenReadError, DeleteError, OpenDirectoryError};
+use directory::error::{IOError, OpenWriteError, OpenReadError, DeleteError, OpenDirectoryError};
use directory::ReadOnlySource;
use directory::shared_vec_slice::SharedVecSlice;
use directory::WritePtr;
@@ -24,13 +24,15 @@ use std::sync::Weak;
use tempdir::TempDir;
fn open_mmap(full_path: &PathBuf) -> result::Result<Option<Arc<Mmap>>, OpenReadError> {
- let convert_file_error = |err: io::Error| if err.kind() == io::ErrorKind::NotFound {
- OpenReadError::FileDoesNotExist(full_path.clone())
- } else {
- OpenReadError::IOError(err)
- };
- let file = File::open(&full_path).map_err(convert_file_error)?;
- let meta_data = file.metadata().map_err(OpenReadError::IOError)?;
+ let file = File::open(&full_path).map_err(|e| {
+ if e.kind() == io::ErrorKind::NotFound {
+ OpenReadError::FileDoesNotExist(full_path.clone())
+ } else {
+ OpenReadError::IOError(IOError::with_path(full_path.to_owned(), e))
+ }
+ })?;
+
+ let meta_data = file.metadata().map_err(|e| IOError::with_path(full_path.to_owned(), e))?;
if meta_data.len() == 0 {
// if the file size is 0, it will not be possible
// to mmap the file, so we return an anonymous mmap_cache
@@ -39,7 +41,7 @@ fn open_mmap(full_path: &PathBuf) -> result::Result<Option<Arc<Mmap>>, OpenReadE
}
match Mmap::open(&file, Protection::Read) {
Ok(mmap) => Ok(Some(Arc::new(mmap))),
- Err(e) => Err(OpenReadError::IOError(e)),
+ Err(e) => Err(IOError::with_path(full_path.to_owned(), e))?,
}
}
@@ -274,7 +276,7 @@ impl Directory for MmapDirectory {
let msg = format!("Failed to acquired write lock \
on mmap cache while reading {:?}",
path);
- OpenReadError::IOError(make_io_err(msg))
+ IOError::with_path(path.to_owned(), make_io_err(msg))
})?;
Ok(mmap_cache
@@ -295,17 +297,17 @@ impl Directory for MmapDirectory {
let mut file = open_res
.map_err(|err| if err.kind() == io::ErrorKind::AlreadyExists {
- OpenWriteError::FileAlreadyExists(PathBuf::from(path))
+ OpenWriteError::FileAlreadyExists(path.to_owned())
} else {
- OpenWriteError::IOError(err)
+ IOError::with_path(path.to_owned(), err).into()
})?;
// making sure the file is created.
- try!(file.flush());
+ file.flush().map_err(|e| IOError::with_path(path.to_owned(), e))?;
// Apparetntly, on some filesystem syncing the parent
// directory is required.
- try!(self.sync_directory());
+ self.sync_directory().map_err(|e| IOError::with_path(path.to_owned(), e))?;
let writer = SafeFileWriter::new(file);
Ok(BufWriter::new(Box::new(writer)))
@@ -320,19 +322,19 @@ impl Directory for MmapDirectory {
let msg = format!("Failed to acquired write lock \
on mmap cache while deleting {:?}",
path);
- DeleteError::IOError(make_io_err(msg))
+ IOError::with_path(path.to_owned(), make_io_err(msg))
})?;
// Removing the entry in the MMap cache.
// The munmap will appear on Drop,
// when the last reference is gone.
mmap_cache.cache.remove(&full_path);
match fs::remove_file(&full_path) {
- Ok(_) => self.sync_directory().map_err(DeleteError::IOError),
+ Ok(_) => self.sync_directory().map_err(|e| IOError::with_path(path.to_owned(), e).into()),
Err(e) => {
if e.kind() == io::ErrorKind::NotFound {
Err(DeleteError::FileDoesNotExist(path.to_owned()))
} else {
- Err(DeleteError::IOError(e))
+ Err(IOError::with_path(path.to_owned(), e).into())
}
}
}
@@ -349,14 +351,14 @@ impl Directory for MmapDirectory {
match File::open(&full_path) {
Ok(mut file) => {
file.read_to_end(&mut buffer)
- .map_err(OpenReadError::IOError)?;
+ .map_err(|e| IOError::with_path(path.to_owned(), e))?;
Ok(buffer)
}
Err(e) => {
if e.kind() == io::ErrorKind::NotFound {
Err(OpenReadError::FileDoesNotExist(path.to_owned()))
} else {
- Err(OpenReadError::IOError(e))
+ Err(IOError::with_path(path.to_owned(), e).into())
}
}
}
diff --git a/src/directory/ram_directory.rs b/src/directory/ram_directory.rs
index 656eb73..1deb758 100644
--- a/src/directory/ram_directory.rs
+++ b/src/directory/ram_directory.rs
@@ -6,7 +6,7 @@ use std::result;
use std::sync::{Arc, RwLock};
use common::make_io_err;
use directory::{Directory, ReadOnlySource};
-use directory::error::{OpenWriteError, OpenReadError, DeleteError};
+use directory::error::{IOError, OpenWriteError, OpenReadError, DeleteError};
use directory::WritePtr;
use super::shared_vec_slice::SharedVecSlice;
@@ -97,7 +97,7 @@ impl InnerDirectory {
directory when trying to read {:?}",
path);
let io_err = make_io_err(msg);
- OpenReadError::IOError(io_err)
+ OpenReadError::IOError(IOError::with_path(path.to_owned(), io_err))
})
.and_then(|readable_map| {
readable_map
@@ -115,7 +115,7 @@ impl InnerDirectory {
directory when trying to delete {:?}",
path);
let io_err = make_io_err(msg);
- DeleteError::IOError(io_err)
+ DeleteError::IOError(IOError::with_path(path.to_owned(), io_err))
})
.and_then(|mut writable_map| match writable_map.remove(path) {
Some(_) => Ok(()),
@@ -163,8 +163,11 @@ impl Directory for RAMDirectory {
fn open_write(&mut self, path: &Path) -> Result<WritePtr, OpenWriteError> {
let path_buf = PathBuf::from(path);
let vec_writer = VecWriter::new(path_buf.clone(), self.fs.clone());
+
+ let exists = self.fs.write(path_buf.clone(), &Vec::new()).map_err(|err| IOError::with_path(path.to_owned(), err))?;
+
// force the creation of the file to mimic the MMap directory.
- if try!(self.fs.write(path_buf.clone(), &Vec::new())) {
+ if exists {
Err(OpenWriteError::FileAlreadyExists(path_buf))
} else {
Ok(BufWriter::new(Box::new(vec_writer)))
diff --git a/src/error.rs b/src/error.rs
index 83077c6..fa13d81 100644
--- a/src/error.rs
+++ b/src/error.rs
@@ -5,85 +5,108 @@ use std::io;
use std::path::PathBuf;
use std::error;
use std::sync::PoisonError;
-use directory::error::{OpenReadError, OpenWriteError, OpenDirectoryError};
+use directory::error::{IOError, OpenReadError, OpenWriteError, OpenDirectoryError};
use query;
use schema;
use fastfield::FastFieldNotAvailableError;
use serde_json;
-
-/// Generic tantivy error.
-///
-/// Any specialized error return in tantivy can be converted in `tantivy::Error`.
-#[derive(Debug)]
-pub enum Error {
- /// Path does not exist.
- PathDoesNotExist(PathBuf),
- /// File already exists, this is a problem when we try to write into a new file.
- FileAlreadyExists(PathBuf),
- /// IO Error
- IOError(io::Error),
- /// A thread holding the locked panicked and poisoned the lock.
- Poisoned,
- /// The data within is corrupted.
- ///
- /// For instance, it contains invalid JSON.
- CorruptedFile(PathBuf, Box<error::Error + Send + Sync>),
- /// Invalid argument was passed by the user.
- InvalidArgument(String),
- /// An Error happened in one of the thread
- ErrorInThread(String),
- /// An Error appeared related to the lack of a field.
- SchemaError(String),
- /// Tried to access a fastfield reader for a field not configured accordingly.
- FastFieldError(FastFieldNotAvailableError),
-}
+error_chain!(
+ errors {
+ PathDoesNotExist(buf: PathBuf) {
+ description("path does not exist")
+ display("path does not exist: '{:?}'", buf)
+ }
+ FileAlreadyExists(buf: PathBuf) {
+ description("file already exists")
+ display("file already exists: '{:?}'", buf)
+ }
+ IOError(err: IOError) {
+ description("an IO error occurred")
+ display("an IO error occurred: '{}'", err)
+ }
+ CorruptedFile(buf: PathBuf) {
+ description("file contains corrupted data")
+ display("file contains corrupted data: '{:?}'", buf)
+ }
+ Poisoned {
+ description("a thread holding the locked panicked and poisoned the lock")
+ }
+ InvalidArgument(arg: String) {
+ description("an invalid argument was passed")
+ display("an invalid argument was passed: '{}'", arg)
+ }
+ ErrorInThread(err: String) {
+ description("an error occurred in a thread")
+ display("an error occurred in a thread: '{}'", err)
+ }
+ SchemaError(field: String) {
+ description("a schema field is missing")
+ display("a schema field is missing: '{}'", field)
+ }
+ FastFieldError(err: FastFieldNotAvailableError) {
+ description("fast field not available")
+ display("fast field not available: '{:?}'", err)
+ }
+ }
+);
impl From<FastFieldNotAvailableError> for Error {
fn from(fastfield_error: FastFieldNotAvailableError) -> Error {
- Error::FastFieldError(fastfield_error)
+ ErrorKind::FastFieldError(fastfield_error).into()
+ }
+}
+
+impl From<IOError> for Error {
+ fn from(io_error: IOError) -> Error {
+ ErrorKind::IOError(io_error).into()
}
}
impl From<io::Error> for Error {
fn from(io_error: io::Error) -> Error {
- Error::IOError(io_error)
+ ErrorKind::IOError(io_error.into()).into()
}
}
impl From<query::QueryParserError> for Error {
fn from(parsing_error: query::QueryParserError) -> Error {
- Error::InvalidArgument(format!("Query is invalid. {:?}", parsing_error))
+ ErrorKind::InvalidArgument(format!("Query is invalid. {:?}", parsing_error)).into()
}
}
impl<Guard> From<PoisonError<Guard>> for Error {
fn from(_: PoisonError<Guard>) -> Error {
- Error::Poisoned
+ ErrorKind::Poisoned.into()
}
}
impl From<OpenReadError> for Error {
fn from(error: OpenReadError) -> Error {
match error {
- OpenReadError::FileDoesNotExist(filepath) => Error::PathDoesNotExist(filepath),
- OpenReadError::IOError(io_error) => Error::IOError(io_error),
+ OpenReadError::FileDoesNotExist(filepath) => {
+ ErrorKind::PathDoesNotExist(filepath).into()
+ }
+ OpenReadError::IOError(io_error) => ErrorKind::IOError(io_error).into(),
}
}
}
impl From<schema::DocParsingError> for Error {
fn from(error: schema::DocParsingError) -> Error {
- Error::InvalidArgument(format!("Failed to parse document {:?}", error))
+ ErrorKind::InvalidArgument(format!("Failed to parse document {:?}", error)).into()
}
}
impl From<OpenWriteError> for Error {
fn from(error: OpenWriteError) -> Error {
match error {
- OpenWriteError::FileAlreadyExists(filepath) => Error::FileAlreadyExists(filepath),
- OpenWriteError::IOError(io_error) => Error::IOError(io_error),
- }
+ OpenWriteError::FileAlreadyExists(filepath) => {
+ ErrorKind::FileAlreadyExists(filepath)
+ }
+ OpenWriteError::IOError(io_error) => ErrorKind::IOError(io_error),
+ }
+ .into()
}
}
@@ -91,17 +114,18 @@ impl From<OpenDirectoryError> for Error {
fn from(error: OpenDirectoryError) -> Error {
match error {
OpenDirectoryError::DoesNotExist(directory_path) => {
- Error::PathDoesNotExist(directory_path)
+ ErrorKind::PathDoesNotExist(directory_path).into()
}
OpenDirectoryError::NotADirectory(directory_path) => {
- Error::InvalidArgument(format!("{:?} is not a directory", directory_path))
- }
+ ErrorKind::InvalidArgument(format!("{:?} is not a directory", directory_path)).into()
+ },
}
}
}
impl From<serde_json::Error> for Error {
fn from(error: serde_json::Error) -> Error {
- Error::IOError(error.into())
+ let io_err = io::Error::from(error);
+ ErrorKind::IOError(io_err.into()).into()
}
}
diff --git a/src/indexer/index_writer.rs b/src/indexer/index_writer.rs
index eb8117a..72b251d 100644
--- a/src/indexer/index_writer.rs
+++ b/src/indexer/index_writer.rs
@@ -9,7 +9,7 @@ use core::SegmentReader;
use indexer::stamper::Stamper;
use datastruct::stacker::Heap;
use directory::FileProtection;
-use Error;
+use error::*;
use Directory;
use fastfield::write_delete_bitset;
use indexer::delete_queue::{DeleteCursor, DeleteQueue};
@@ -22,7 +22,6 @@ use indexer::SegmentEntry;
use indexer::SegmentWriter;
use postings::DocSet;
use postings::SegmentPostingsOption;
-use Result;
use schema::Document;
use schema::Schema;
use schema::Term;
@@ -325,19 +324,17 @@ impl IndexWriter {
let former_workers_handles = mem::replace(&mut self.workers_join_handle, vec![]);
for join_handle in former_workers_handles {
- try!(join_handle
+ join_handle
.join()
.expect("Indexing Worker thread panicked")
- .map_err(|e| {
- Error::ErrorInThread(format!("Error in indexing worker thread. {:?}", e))
- }));
+ .chain_err(|| ErrorKind::ErrorInThread("Error in indexing worker thread.".into()))?;
}
drop(self.workers_join_handle);
let result =
self.segment_updater
.wait_merging_thread()
- .map_err(|_| Error::ErrorInThread("Failed to join merging thread.".to_string()));
+ .chain_err(|| ErrorKind::ErrorInThread("Failed to join merging thread.".into()));
if let Err(ref e) = result {
error!("Some merging thread failed {:?}", e);
@@ -527,12 +524,13 @@ impl IndexWriter {
for worker_handle in former_workers_join_handle {
let indexing_worker_result =
- try!(worker_handle
+ worker_handle
.join()
- .map_err(|e| Error::ErrorInThread(format!("{:?}", e))));
- try!(indexing_worker_result);
+ .map_err(|e| Error::from(ErrorKind::ErrorInThread(format!("{:?}", e))))?;
+
+ indexing_worker_result?;
// add a new worker for the next generation.
- try!(self.add_indexing_worker());
+ self.add_indexing_worker()?;
}
diff --git a/src/indexer/merger.rs b/src/indexer/merger.rs
index 4c19254..ab82deb 100644
--- a/src/indexer/merger.rs
+++ b/src/indexer/merger.rs
@@ -1,4 +1,4 @@
-use {Error, Result};
+use error::*;
use core::SegmentReader;
use core::Segment;
use DocId;
@@ -161,7 +161,7 @@ impl IndexMerger {
let error_msg = format!("Failed to find a u64_reader for field {:?}",
field);
error!("{}", error_msg);
- return Err(Error::SchemaError(error_msg));
+ bail!(ErrorKind::SchemaError(error_msg));
}
}
}
diff --git a/src/indexer/segment_updater.rs b/src/indexer/segment_updater.rs
index 5446132..fad6a4c 100644
--- a/src/indexer/segment_updater.rs
+++ b/src/indexer/segment_updater.rs
@@ -7,7 +7,7 @@ use core::SegmentMeta;
use core::SerializableSegment;
use directory::Directory;
use indexer::stamper::Stamper;
-use Error;
+use error::*;
use futures_cpupool::CpuPool;
use futures::Future;
use futures::Canceled;
@@ -19,7 +19,6 @@ use indexer::MergeCandidate;
use indexer::merger::IndexMerger;
use indexer::SegmentEntry;
use indexer::SegmentSerializer;
-use Result;
use futures_cpupool::CpuFuture;
use serde_json;
use indexer::delete_queue::DeleteCursor;
@@ -117,7 +116,7 @@ fn perform_merge(segment_ids: &[SegmentId],
error!("Error, had to abort merge as some of the segment is not managed anymore.");
let msg = format!("Segment {:?} requested for merge is not managed.",
segment_id);
- return Err(Error::InvalidArgument(msg));
+ bail!(ErrorKind::InvalidArgument(msg));
}
}
@@ -447,8 +446,7 @@ impl SegmentUpdater {
for (_, merging_thread_handle) in new_merging_threads {
merging_thread_handle
.join()
- .map(|_| ())
- .map_err(|_| Error::ErrorInThread("Merging thread failed.".to_string()))?
+ .map_err(|_| ErrorKind::ErrorInThread("Merging thread failed.".into()))?;
}
// Our merging thread may have queued their completed
self.run_async(move |_| {}).wait()?;
diff --git a/src/lib.rs b/src/lib.rs
index 8995326..00f4a7b 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -36,6 +36,9 @@ extern crate serde_derive;
extern crate log;
#[macro_use]
+extern crate error_chain;
+
+#[macro_use]
extern crate version;
extern crate fst;
extern crate byteorder;