javascriptmeteorhalting-problem

Meteor - detecting infinite loop


Here's the essence of some code (with associated data) for a Meteor application for counting things. Counts can be linked together so that one can increase another:

// The counting and linking code.
Meteor.methods({
    'counts.increment'(countId) {
        const count = Counts.findOne(countId);
        Counts.update(countId,{ $inc: { count: 1 } })
        Meteor.call('counts.check-links',count._id);
    },
    'counts.check-links'(countId){
        var count = Counts.findOne(countId);
        count.links.forEach(function (linkId) {
            updated = false;
            const link = Links.findOne(linkId);
            const primary = Counts.findOne(link.primary);
            const secondary = Counts.findOne(link.secondary);
            if (primary.count == link.level) {
                updated = true;
                Counts.update(secondary._id, {$inc: {count: 1}});
            }
            if (updated) {
                Meteor.call('counts.check-links',secondary._id);
            }
        })
    }
})

// Some data...
Count: {
  _id: 1,
  value: 0,
  name: A,
  links: [3]
}

Count: {
  _id: 2,
  value: 0,
  name: B,
  links: [4]
}

Link: {
  _id: 3,
  primary: 1,
  secondary: 2
}

Link: {
  _id: 4,
  primary: 2,
  secondary: 1
}

So, if Meteor.call('projects.increment',1) is called this code will crash as each count is linked to the other. Detecting such a setup could be rather difficult as there could be very complex arrangements of counts and the links can also decrease, set to zero, operate every N counts &c. &c. For the purposes of asking this question that shouldn't matter, though.

One possibility I thought of would be to add a counter within counts.check-links which would stop execution after an arbitrary number of loops, e.g. 5. Presumably, to guard against tampering the value of this counter would have to be stored in the database and acted upon via a Meteor method. It would need to be reset at the conclusion of any sequence of check-links calls.

I'm not sure if this is the best idea or if so how might be a good way to implement it, and so I would be interested to know if anyone has any suggestions.


Solution

  • You could create a set of all objects ("Counts") already visited; so if you follow a link to such an object, you can avoid handling it again, thus running into the infinite recursion.

    EDIT: Example I'm not familiar with meteor, so please forgive if it doesn't work as expected... This is a common problem for all programing languages that allow for pointers of object references, though, and the solution follows a similar pattern.

    // The counting and linking code.
    Meteor.methods({
      ...
    'counts.check-links'(countId, alreadyVisited){
    
        if (!alreadyVisited) alreadyVisited = {};
        if (alreadyVisited[countId]) return;
        alreadyVisited[countId] = true;
    
        var count = Counts.findOne(countId);
        count.links.forEach(function (linkId) {
            updated = false;
            const link = Links.findOne(linkId);
            const primary = Counts.findOne(link.primary);
            const secondary = Counts.findOne(link.secondary);
            if (primary.count == link.level) {
                updated = true;
                Counts.update(secondary._id, {$inc: {count: 1}});
            }
            if (updated) {
                Meteor.call('counts.check-links',secondary._id, alreadyVisited);
            }
        })
    }