Giter Club home page Giter Club logo

Comments (5)

xffxff avatar xffxff commented on August 28, 2024

@Chronostasys Would it be possible for you to share a minimum, reproducible code with us? This would help us to better understand the issue

from salsa.

Chronostasys avatar Chronostasys commented on August 28, 2024

@Chronostasys Would it be possible for you to share a minimum, reproducible code with us? This would help us to better understand the issue

Not yet. I've tried it yesterday, as the real-world case is really complecated, it may take more time for me to find out how to reproduce it on a sample project.

from salsa.

Chronostasys avatar Chronostasys commented on August 28, 2024

After moving the cycle handler to another participant function in the cycle, the panic position changed:

thread 'main' panicked at 'expected a query assigned by `compile_dry_file(11)`, not `Program_emit(11)`'

and during recover, the participants be like:

["compile_dry_file(11)", "Program_emit(11)", "compile_dry_file(12)", "Program_emit(12)", "compile_dry_file(15)", "Program_emit(15)"]

Note that in my case, panic recovery logic is triggered three times in a single revision.

from salsa.

Chronostasys avatar Chronostasys commented on August 28, 2024

@Chronostasys Would it be possible for you to share a minimum, reproducible code with us? This would help us to better understand the issue

@xffxff
https://github.com/Chronostasys/salsa-panic-example

from salsa.

xffxff avatar xffxff commented on August 28, 2024

A simpler example to reproduce this issue can be found at https://gist.github.com/xffxff/47dbd41a078c8e705aa35d7a9d6f1303. Here's a brief version:

#[salsa::tracked(jar = Jar)]
fn memoized(db: &dyn Db, input: MyInput) -> u32 {
    memoized_a(db, MyTracked::new(db, input.field(db)))
}

#[salsa::tracked(jar = Jar)]
fn memoized_a(db: &dyn Db, tracked: MyTracked) -> u32 {
    MyTracked::new(db, 0);
    return memoized_b(db, tracked);
}

fn recovery_fn(db: &dyn Db, cycle: &salsa::Cycle, input: MyTracked) -> u32 {
    0
}

#[salsa::tracked(jar = Jar, recovery_fn=recovery_fn)]
fn memoized_b(db: &dyn Db, tracked: MyTracked) -> u32 {
    tracked.field(db) + memoized_a(db, tracked)
}

This code will fail with the following error:

thread 'cycle_memoized' panicked at 'assertion failed: `(left == right)`
  left: `DatabaseKeyIndex { ingredient_index: IngredientIndex(5), key_index: Id { value: 1 } }`,
 right: `DatabaseKeyIndex { ingredient_index: IngredientIndex(6), key_index: Id { value: 1 } }`

The issue is Salsa thinks the dependencies (inputs_outputs) of memoized_b(MyTracked { [salsa id]: 0 }) to be:

QueryEdges {
    input_outputs: [
        (
            Input,
            MyTracked(),
        ),
        (
            Output,
            MyTracked(1),
        ),
        (
            Output,
            field(MyTracked { [salsa id]: 1 }),
        ),
        (
            Input,
            field(MyTracked { [salsa id]: 0 }),
        ),
    ],
},

The panic occurs when the query memoized_b(MyTracked { [salsa id]: 0 }) tries to mark the output MyTracked(1) as valid. However, the output MyTracked(1) isn't created by memoized_b(MyTracked { [salsa id]: 0 }), but by memoized_a(MyTracked { [salsa id]: 0 }). The relevant code is:

db.mark_validated_output(database_key_index, dependency_index);

The dependencies of memoized_b(MyTracked { [salsa id]: 0 }) orginates from the following code:

dg.for_each_cycle_participant(from_id, &mut from_stack, database_key_index, to_id, |aqs| {
aqs.iter_mut()
.skip_while(|aq| {
match db.cycle_recovery_strategy(aq.database_key_index.ingredient_index) {
CycleRecoveryStrategy::Panic => true,
CycleRecoveryStrategy::Fallback => false,
}
})
.for_each(|aq| {
log::debug!("marking {:?} for fallback", aq.database_key_index.debug(db));
aq.take_inputs_from(&cycle_query);
assert!(aq.cycle.is_none());
aq.cycle = Some(cycle.clone());
});
});

pub(crate) fn take_inputs_from(&mut self, cycle_query: &ActiveQuery) {
self.changed_at = cycle_query.changed_at;
self.durability = cycle_query.durability;
self.input_outputs = cycle_query.input_outputs.clone();
}

When a cycle is detected, the query with recovery_fn, memoized_b(MyTracked { [salsa id]: 0 }) in this case, takes all the inputs and outputs from the cycle participants. However, as the function name take_inputs_from suggests, it might be more appropriate to only take the inputs from the cycle participants. (This might be a bug introduced by #413)

pub(crate) fn take_inputs_from(&mut self, cycle_query: &ActiveQuery) {
    self.changed_at = cycle_query.changed_at;
    self.durability = cycle_query.durability;
    self.input_outputs = cycle_query.input_outputs.iter().filter(|(edge_kind, database_key_index)| {
        *edge_kind == EdgeKind::Input
    })
    .copied().collect::<FxIndexSet<(EdgeKind, DependencyIndex)>>();
}

I'm uncertain if this is the correct solution. Furthermore, I'm unclear why the query withrecovery_fn in a cycle needs to take all the inputs from the cycle participants.

from salsa.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.