Non wait on json path applied to scalars (#118)

This commit is contained in:
Mike Voronov 2021-06-10 13:00:11 +03:00 committed by GitHub
parent b2919b1509
commit dc1582d02e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 149 additions and 34 deletions

View File

@ -1,7 +1,33 @@
## Version 0.10.4 (2021-06-10)
- json path applied to scalar values becomes non-joinable ([PR 118](https://github.com/fluencelabs/aquavm/pull/118))
## Version 0.10.3 (2021-06-09)
- `%last_error%` includes `peer_id` now, that contains id of a peer where an error occurred ([PR 117](https://github.com/fluencelabs/aquavm/pull/117)).
## Version 0.10.2-0.10.1 (2021-06-04)
- improved logger initialization and interface for wasm-bindgen target ([PR 116](https://github.com/fluencelabs/aquavm/pull/116), [PR 115](https://github.com/fluencelabs/aquavm/pull/115)).
## Version 0.10.0 (2021-06-09)
- `%last_error%` becomes an object of type
```rust
pub struct LastError {
/// text representation of an instruction that caused the last error
pub instruction: String,
/// text representation of an error message
pub msg: String,
}
```
and it's possible to address its fields separately: `%last_error%.$.instruction`, `%last_error%.$.msg` ([PR 112](https://github.com/fluencelabs/aquavm/pull/112)).
## Version 0.1.3 (2020-11-11)
- Switched to the new LALRPOP parser ([PR 13](https://github.com/fluencelabs/air/pull/13)):
- arguments should be wrapped wit square braces []
- arguments should be wrapped with square braces []
- empty results in call allowed and lead to forget a call result
- Added a few benchmarks

View File

@ -25,6 +25,7 @@ use super::ExecutionError;
use super::ExecutionResult;
use super::ExecutionTraceCtx;
use crate::contexts::execution::LastErrorDescriptor;
use crate::execution::joinable::Joinable;
use crate::joinable_call;
use crate::log_instruction;
use crate::SecurityTetraplet;

View File

@ -19,6 +19,7 @@ use super::ExecutionCtx;
use super::ExecutionError;
use super::ExecutionResult;
use super::ExecutionTraceCtx;
use crate::execution::joinable::Joinable;
use crate::joinable;
use crate::log_instruction;

View File

@ -19,6 +19,7 @@ use super::ExecutionCtx;
use super::ExecutionError;
use super::ExecutionResult;
use super::ExecutionTraceCtx;
use crate::execution::joinable::Joinable;
use crate::joinable;
use crate::log_instruction;

View File

@ -155,7 +155,7 @@ macro_rules! log_instruction {
macro_rules! joinable_call {
($cmd:expr, $exec_ctx:expr) => {
match $cmd {
Err(e) if crate::execution::air::is_joinable_error_type(&e) => {
Err(e) if e.is_joinable() => {
$exec_ctx.subtree_complete = false;
return Ok(());
}
@ -169,39 +169,10 @@ macro_rules! joinable_call {
macro_rules! joinable {
($cmd:expr, $exec_ctx:expr) => {
match $cmd {
Err(e) if crate::execution::air::is_joinable_error_type(&e) => {
Err(e) if e.is_joinable() => {
return Ok(());
}
v => v,
}
};
}
macro_rules! log_join {
($($args:tt)*) => {
log::info!(target: crate::log_targets::JOIN_BEHAVIOUR, $($args)*)
}
}
/// Returns true, if supplied error is related to variable not found errors type.
/// Print log if this is joinable error type.
#[rustfmt::skip::macros(log_join)]
fn is_joinable_error_type(exec_error: &ExecutionError) -> bool {
use ExecutionError::*;
match exec_error {
VariableNotFound(var_name) => {
log_join!(" waiting for an argument with name '{}'", var_name);
true
}
JValueJsonPathError(value, json_path, _) => {
log_join!(" waiting for an argument with path '{}' on jvalue '{:?}'", json_path, value);
true
}
JValueStreamJsonPathError(stream, json_path, _) => {
log_join!(" waiting for an argument with path '{}' on stream '{:?}'", json_path, stream);
true
}
_ => false,
}
}

View File

@ -14,6 +14,7 @@
* limitations under the License.
*/
use super::Joinable;
use crate::build_targets::CallServiceResult;
use crate::contexts::execution::ResolvedCallResult;
use crate::contexts::execution_trace::ExecutedState;
@ -131,6 +132,33 @@ impl ExecutionError {
}
}
macro_rules! log_join {
($($args:tt)*) => {
log::info!(target: crate::log_targets::JOIN_BEHAVIOUR, $($args)*)
}
}
#[rustfmt::skip::macros(log_join)]
impl Joinable for ExecutionError {
/// Returns true, if supplied error is related to variable not found errors type.
/// Print log if this is joinable error type.
fn is_joinable(&self) -> bool {
use ExecutionError::*;
match self {
VariableNotFound(var_name) => {
log_join!(" waiting for an argument with name '{}'", var_name);
true
}
JValueStreamJsonPathError(stream, json_path, _) => {
log_join!(" waiting for an argument with path '{}' on stream '{:?}'", json_path, stream);
true
}
_ => false,
}
}
}
impl From<std::convert::Infallible> for ExecutionError {
fn from(_: std::convert::Infallible) -> Self {
unreachable!()

View File

@ -0,0 +1,27 @@
/*
* Copyright 2020 Fluence Labs Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/// This trait is intended to differentiate between joinable and non-joinable objects.
/// Joinable objects are those that interpreter should wait on. F.e. if at least one of
/// arguments of a call instructions is joinable, the interpreter won't execute such
/// call and won't write any state for it in data. This is needed to handle collecting
/// variable from different peers in parallel.
///
/// At the moment, this trait's applied only to errors.
pub(crate) trait Joinable {
/// Return true, if supplied object is joinable
fn is_joinable(&self) -> bool;
}

View File

@ -17,11 +17,13 @@
mod air;
mod boxed_value;
mod errors;
mod joinable;
mod utils;
pub(super) use self::air::ExecutableInstruction;
pub(super) use self::air::FoldState;
pub(super) use errors::ExecutionError;
pub(self) use joinable::Joinable;
use std::rc::Rc;

View File

@ -23,7 +23,7 @@ use air_test_utils::ExecutionTrace;
use serde_json::json;
#[test]
fn non_wait_on_json_path() {
fn dont_wait_on_json_path() {
let status = json!({
"err_msg": "",
"is_authenticated": 1,
@ -106,3 +106,62 @@ fn wait_on_stream_json_path_by_id() {
assert_eq!(res.ret_code, 0);
assert_eq!(trace.len(), 2); // par and the first call emit traces, second call doesn't
}
#[test]
fn dont_wait_on_json_path_on_scalars() {
let array = json!([1, 2, 3, 4, 5]);
let object = json!({
"err_msg": "",
"is_authenticated": 1,
"ret_code": 0,
});
let variables = maplit::hashmap!(
"array".to_string() => array.to_string(),
"object".to_string() => object.to_string(),
);
let set_variables_call_service = set_variables_call_service(variables);
let set_variable_peer_id = "set_variable";
let mut set_variable_vm = create_avm(set_variables_call_service, set_variable_peer_id);
let array_consumer_peer_id = "array_consumer_peer_id";
let mut array_consumer = create_avm(unit_call_service(), array_consumer_peer_id);
let object_consumer_peer_id = "object_consumer_peer_id";
let mut object_consumer = create_avm(unit_call_service(), object_consumer_peer_id);
let script = format!(
r#"
(seq
(seq
(call "{0}" ("" "") ["array"] array)
(call "{0}" ("" "") ["object"] object)
)
(par
(call "{1}" ("" "") [array.$.[5]!] auth_result)
(call "{2}" ("" "") [object.$.non_exist_path])
)
)
"#,
set_variable_peer_id, array_consumer_peer_id, object_consumer_peer_id,
);
let init_peer_id = "asd";
let res = call_vm!(set_variable_vm, init_peer_id, &script, "", "");
let array_res = call_vm!(array_consumer, init_peer_id, &script, "", res.data.clone());
assert_eq!(array_res.ret_code, 1006);
assert_eq!(
array_res.error_message,
r#"variable with path '$.[5]' not found in '[1,2,3,4,5]' with an error: 'json value not set'"#
);
let object_res = call_vm!(object_consumer, init_peer_id, script, "", res.data);
assert_eq!(object_res.ret_code, 1006);
assert_eq!(
object_res.error_message,
r#"variable with path '$.non_exist_path' not found in '{"err_msg":"","is_authenticated":1,"ret_code":0}' with an error: 'json value not set'"#
);
}

View File

@ -17,7 +17,6 @@
use air_test_utils::call_vm;
use air_test_utils::create_avm;
use air_test_utils::echo_string_call_service;
use air_test_utils::ExecutionTrace;
#[test]
fn json_path_not_allowed_for_non_objects_and_arrays() {