Skip to content

Don't stop the dirty scripts when an OOM occurs midway through execution#3030

Merged
rjd15372 merged 3 commits into
valkey-io:unstablefrom
enjoy-binbin:dirty_scripts
Jan 12, 2026
Merged

Don't stop the dirty scripts when an OOM occurs midway through execution#3030
rjd15372 merged 3 commits into
valkey-io:unstablefrom
enjoy-binbin:dirty_scripts

Conversation

@enjoy-binbin

Copy link
Copy Markdown
Member

Before #2858, we has this check:

static int scriptVerifyOOM(scriptRunCtx *run_ctx, char **err) {
    if (run_ctx->flags & SCRIPT_ALLOW_OOM) {
        /* Allow running any command even if OOM reached */
        return C_OK;
    }

    /* If we reached the memory limit configured via maxmemory, commands that
     * could enlarge the memory usage are not allowed, but only if this is the
     * first write in the context of this script, otherwise we can't stop
     * in the middle. */

    if (server.maxmemory &&                          /* Maxmemory is actually enabled. */
        !mustObeyClient(run_ctx->original_client) && /* Don't care about mem for replicas or AOF. */
        !(run_ctx->flags & SCRIPT_WRITE_DIRTY) &&    /* Script had no side effects so far. */
        server.pre_command_oom_state &&              /* Detected OOM when script start. */
        (run_ctx->c->cmd->flags & CMD_DENYOOM)) {
        *err = sdsdup(shared.oomerr->ptr);
        return C_ERR;
    }

    return C_OK;
}

If we reached the memory limit configured via maxmemory, commands that
could enlarge the memory usage are not allowed, but only if this is the
first write in the context of this script, otherwise we can't stop
in the middle.

Before valkey-io#2858, we has this check:
```
static int scriptVerifyOOM(scriptRunCtx *run_ctx, char **err) {
    if (run_ctx->flags & SCRIPT_ALLOW_OOM) {
        /* Allow running any command even if OOM reached */
        return C_OK;
    }

    /* If we reached the memory limit configured via maxmemory, commands that
     * could enlarge the memory usage are not allowed, but only if this is the
     * first write in the context of this script, otherwise we can't stop
     * in the middle. */

    if (server.maxmemory &&                          /* Maxmemory is actually enabled. */
        !mustObeyClient(run_ctx->original_client) && /* Don't care about mem for replicas or AOF. */
        !(run_ctx->flags & SCRIPT_WRITE_DIRTY) &&    /* Script had no side effects so far. */
        server.pre_command_oom_state &&              /* Detected OOM when script start. */
        (run_ctx->c->cmd->flags & CMD_DENYOOM)) {
        *err = sdsdup(shared.oomerr->ptr);
        return C_ERR;
    }

    return C_OK;
}
```

If we reached the memory limit configured via maxmemory, commands that
could enlarge the memory usage are not allowed, but only if this is the
first write in the context of this script, otherwise we can't stop
in the middle.

Signed-off-by: Binbin <binloveplay1314@qq.com>
Signed-off-by: Binbin <binloveplay1314@qq.com>
@enjoy-binbin

Copy link
Copy Markdown
Member Author

@rjd15372 did you do this on purpose? I'm not sure if the old behavior was correct (it might cause the script to use too much memory), but we are allow to do this before.

    test "Don't stop the dirty scripts when an OOM occurs midway through execution" {
        r flushall
        r config set maxmemory 1
        r eval {
            server.call('get', KEYS[1])
            server.call('del', KEYS[1])
            server.call('set', KEYS[1], ARGV[1])
        } 1 foo bar
       assert_equal bar [r get foo]
    }

@codecov

codecov Bot commented Jan 8, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 74.26%. Comparing base (35fdcea) to head (ff8f854).
⚠️ Report is 7 commits behind head on unstable.

Additional details and impacted files
@@             Coverage Diff              @@
##           unstable    #3030      +/-   ##
============================================
- Coverage     74.38%   74.26%   -0.12%     
============================================
  Files           129      129              
  Lines         70972    70988      +16     
============================================
- Hits          52791    52719      -72     
- Misses        18181    18269      +88     
Files with missing lines Coverage Δ
src/module.c 26.51% <100.00%> (+0.01%) ⬆️

... and 32 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Comment thread appendonly Outdated
Signed-off-by: Binbin <binloveplay1314@qq.com>
@rjd15372

Copy link
Copy Markdown
Member

@rjd15372 did you do this on purpose? I'm not sure if the old behavior was correct (it might cause the script to use too much memory), but we are allow to do this before.

No, this was an oversight from my part. Thanks for catching this.

@rjd15372 rjd15372 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for catching this!

@rjd15372 rjd15372 merged commit f0d9810 into valkey-io:unstable Jan 12, 2026
21 of 24 checks passed
@enjoy-binbin enjoy-binbin deleted the dirty_scripts branch January 12, 2026 17:32
@madolson

Copy link
Copy Markdown
Member

@rjd15372 The tests were failing when you merged this. Ideally don't do that in the future.

@enjoy-binbin

Copy link
Copy Markdown
Member Author

sorry, i didn't realize the external tests are failing before. I don't know how i missed it, my bad.

@rjd15372

Copy link
Copy Markdown
Member

@madolson I totally missed that tests were failing otherwise I wouldn't have merged the PR. My bad!

harrylin98 pushed a commit to harrylin98/valkey_forked that referenced this pull request Feb 19, 2026
…ion (valkey-io#3030)

Before valkey-io#2858, we has this check:
```
static int scriptVerifyOOM(scriptRunCtx *run_ctx, char **err) {
    if (run_ctx->flags & SCRIPT_ALLOW_OOM) {
        /* Allow running any command even if OOM reached */
        return C_OK;
    }

    /* If we reached the memory limit configured via maxmemory, commands that
     * could enlarge the memory usage are not allowed, but only if this is the
     * first write in the context of this script, otherwise we can't stop
     * in the middle. */

    if (server.maxmemory &&                          /* Maxmemory is actually enabled. */
        !mustObeyClient(run_ctx->original_client) && /* Don't care about mem for replicas or AOF. */
        !(run_ctx->flags & SCRIPT_WRITE_DIRTY) &&    /* Script had no side effects so far. */
        server.pre_command_oom_state &&              /* Detected OOM when script start. */
        (run_ctx->c->cmd->flags & CMD_DENYOOM)) {
        *err = sdsdup(shared.oomerr->ptr);
        return C_ERR;
    }

    return C_OK;
}
```

If we reached the memory limit configured via maxmemory, commands that
could enlarge the memory usage are not allowed, but only if this is the
first write in the context of this script, otherwise we can't stop
in the middle.

---------

Signed-off-by: Binbin <binloveplay1314@qq.com>
hpatro pushed a commit to hpatro/valkey that referenced this pull request Mar 5, 2026
…ion (valkey-io#3030)

Before valkey-io#2858, we has this check:
```
static int scriptVerifyOOM(scriptRunCtx *run_ctx, char **err) {
    if (run_ctx->flags & SCRIPT_ALLOW_OOM) {
        /* Allow running any command even if OOM reached */
        return C_OK;
    }

    /* If we reached the memory limit configured via maxmemory, commands that
     * could enlarge the memory usage are not allowed, but only if this is the
     * first write in the context of this script, otherwise we can't stop
     * in the middle. */

    if (server.maxmemory &&                          /* Maxmemory is actually enabled. */
        !mustObeyClient(run_ctx->original_client) && /* Don't care about mem for replicas or AOF. */
        !(run_ctx->flags & SCRIPT_WRITE_DIRTY) &&    /* Script had no side effects so far. */
        server.pre_command_oom_state &&              /* Detected OOM when script start. */
        (run_ctx->c->cmd->flags & CMD_DENYOOM)) {
        *err = sdsdup(shared.oomerr->ptr);
        return C_ERR;
    }

    return C_OK;
}
```

If we reached the memory limit configured via maxmemory, commands that
could enlarge the memory usage are not allowed, but only if this is the
first write in the context of this script, otherwise we can't stop
in the middle.

---------

Signed-off-by: Binbin <binloveplay1314@qq.com>
Signed-off-by: Harkrishn Patro <bunty.hari@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

4 participants