Add error tracing support in Aspect implementation

This removes the parallelization feature from the Aspect codebase as
std::error::Error does not implement Send, so we cannot send the error
from a child thread to a parent thread.

This is clearly not an optimal implementation now, but we have hook
non-aborting-error tracing support, which is more important than
parallelization support, at least in this early stage of development.

An issue has to be opened for re-implementing parallelization of hooks.
This commit is contained in:
Matthias Beyer 2016-05-09 16:24:53 +02:00
parent 6c7d6c29ea
commit a42b6a10db

View file

@ -1,3 +1,5 @@
use libimagerror::trace::trace_error;
use store::FileLockEntry; use store::FileLockEntry;
use storeid::StoreId; use storeid::StoreId;
use hook::Hook; use hook::Hook;
@ -38,34 +40,32 @@ impl Aspect {
impl StoreIdAccessor for Aspect { impl StoreIdAccessor for Aspect {
fn access(&self, id: &StoreId) -> HookResult<()> { fn access(&self, id: &StoreId) -> HookResult<()> {
use crossbeam;
let accessors : Vec<HDA> = self.hooks.iter().map(|h| h.accessor()).collect(); let accessors : Vec<HDA> = self.hooks.iter().map(|h| h.accessor()).collect();
if !accessors.iter().all(|a| is_match!(*a, HDA::StoreIdAccess(_))) { if !accessors.iter().all(|a| is_match!(*a, HDA::StoreIdAccess(_))) {
return Err(HE::new(HEK::AccessTypeViolation, None)); return Err(HE::new(HEK::AccessTypeViolation, None));
} }
let threads : Vec<HookResult<()>> = accessors accessors
.iter() .iter()
.map(|accessor| { .fold(Ok(()), |acc, accessor| {
crossbeam::scope(|scope| { acc.and_then(|_| {
scope.spawn(|| { let res = match accessor {
match *accessor { &HDA::StoreIdAccess(accessor) => accessor.access(id),
HDA::StoreIdAccess(accessor) => accessor.access(id),
_ => unreachable!(), _ => unreachable!(),
} };
.map_err(|_| ()) // TODO: We're losing the error cause here
})
})
})
.map(|i| i.join().map_err(|_| HE::new(HEK::HookExecutionError, None)))
.collect();
threads match res {
.into_iter() Ok(res) => Ok(res),
.fold(Ok(()), |acc, elem| { Err(e) => {
acc.and_then(|a| { if !e.is_aborting() {
elem.map(|_| a).map_err(|_| HE::new(HEK::HookExecutionError, None)) trace_error(&e);
// ignore error if it is not aborting, as we printed it already
Ok(())
} else {
Err(e)
}
}
}
}) })
}) })
} }
@ -83,52 +83,63 @@ impl MutableHookDataAccessor for Aspect {
return Err(HE::new(HEK::AccessTypeViolation, None)); return Err(HE::new(HEK::AccessTypeViolation, None));
} }
for accessor in accessors {
match accessor {
HDA::MutableAccess(accessor) => try!(accessor.access_mut(fle)),
// TODO: Naiive implementation. // TODO: Naiive implementation.
// More sophisticated version would check whether there are _chunks_ of // More sophisticated version would check whether there are _chunks_ of
// NonMutableAccess accessors and execute these chunks in parallel. We do not have // NonMutableAccess accessors and execute these chunks in parallel. We do not have
// performance concerns yet, so this is okay. // performance concerns yet, so this is okay.
HDA::NonMutableAccess(accessor) => try!(accessor.access(fle)), accessors.iter().fold(Ok(()), |acc, accessor| {
acc.and_then(|_| {
let res = match accessor {
&HDA::MutableAccess(ref accessor) => accessor.access_mut(fle),
&HDA::NonMutableAccess(ref accessor) => accessor.access(fle),
_ => unreachable!(), _ => unreachable!(),
} };
}
match res {
Ok(res) => Ok(res),
Err(e) => {
if !e.is_aborting() {
trace_error(&e);
// ignore error if it is not aborting, as we printed it already
Ok(()) Ok(())
} else {
Err(e)
}
}
}
})
})
} }
} }
impl NonMutableHookDataAccessor for Aspect { impl NonMutableHookDataAccessor for Aspect {
fn access(&self, fle: &FileLockEntry) -> HookResult<()> { fn access(&self, fle: &FileLockEntry) -> HookResult<()> {
use crossbeam;
let accessors : Vec<HDA> = self.hooks.iter().map(|h| h.accessor()).collect(); let accessors : Vec<HDA> = self.hooks.iter().map(|h| h.accessor()).collect();
if !accessors.iter().all(|a| is_match!(*a, HDA::NonMutableAccess(_))) { if !accessors.iter().all(|a| is_match!(*a, HDA::NonMutableAccess(_))) {
return Err(HE::new(HEK::AccessTypeViolation, None)); return Err(HE::new(HEK::AccessTypeViolation, None));
} }
let threads : Vec<HookResult<()>> = accessors accessors
.iter() .iter()
.map(|accessor| { .fold(Ok(()), |acc, accessor| {
crossbeam::scope(|scope| { acc.and_then(|_| {
scope.spawn(|| { let res = match accessor {
match *accessor { &HDA::NonMutableAccess(accessor) => accessor.access(fle),
HDA::NonMutableAccess(accessor) => accessor.access(fle),
_ => unreachable!(), _ => unreachable!(),
} };
.map_err(|_| ()) // TODO: We're losing the error cause here
})
})
})
.map(|i| i.join().map_err(|_| HE::new(HEK::HookExecutionError, None)))
.collect();
threads match res {
.into_iter() Ok(res) => Ok(res),
.fold(Ok(()), |acc, elem| { Err(e) => {
acc.and_then(|a| { if !e.is_aborting() {
elem.map(|_| a).map_err(|_| HE::new(HEK::HookExecutionError, None)) trace_error(&e);
// ignore error if it is not aborting, as we printed it already
Ok(())
} else {
Err(e)
}
}
}
}) })
}) })
} }