9-Submission 数据模型与字段编码
9-Submission 数据模型与字段编码

9-Submission 数据模型与字段编码

本文档详细阐述 Judge0 系统中 Submission(提交) 数据模型的核心架构、字段设计及其 Base64 编码机制。作为代码执行系统的核心实体,Submission 承载着从源码提交到结果返回的完整生命周期管理。

数据模型概览

Submission 是 Judge0 系统中处理代码执行请求的核心模型。它通过 active_record 与 PostgreSQL 数据库交互,并在 IsolateJob 的配合下完成沙箱环境中的代码编译与执行。

classDiagram
    class Submission {
        +integer id
        +text source_code
        +integer language_id
        +text stdin
        +text expected_output
        +text stdout
        +integer status_id
        +decimal time
        +integer memory
        +string token
        +datetime created_at
        +datetime finished_at
        +string compiler_options
        +string command_line_arguments
        +boolean enable_network
        +binary additional_files
    }

    class Language {
        +integer id
        +string name
        +string compile_cmd
        +string run_cmd
        +boolean is_archived
    }

    class Status {
        +integer id
        +string name
        <<enumeration>>
    }

    class IsolateJob {
        +perform(submission_id)
        +compile()
        +run()
        +verify()
    }

    class Base64Service {
        +encode(text)
        +decode(text)
    }

    Submission --> Language : belongs_to
    Submission --> Status : belongs_to
    IsolateJob --> Submission : processes
    Submission --> Base64Service : uses encoding

Sources: submission.rb, schema.rb

核心字段分类

Submission 表包含 38 个字段,按功能可划分为以下五大类别:

类别 字段 说明
标识与关联 id, token, language_id, status_id 唯一标识与关联关系
代码与输入输出 source_code, stdin, expected_output, stdout, stderr, compile_output 代码执行的核心数据
执行资源限制 cpu_time_limit, cpu_extra_time, wall_time_limit, memory_limit, stack_limit 资源配额控制
执行结果 time, memory, exit_code, exit_signal, message, wall_time 执行后的度量数据
生命周期管理 created_at, queued_at, started_at, finished_at, updated_at, queue_host, execution_host 状态追踪

Sources: schema.rb

Base64 编码机制

设计原理

Judge0 采用 Base64 编码处理所有文本数据字段,以支持二进制安全传输和特殊字符处理。这一机制确保了代码源码、标准输入输出等数据在 HTTP 传输过程中的完整性和可靠性。

flowchart LR
    subgraph ClientSide
        A[原始源码] -->|UTF-8 编码| B[Base64 编码字符串]
        C[原始输入] -->|UTF-8 编码| D[Base64 编码字符串]
    end

    subgraph Transport
        B -->|HTTP POST| E[API Gateway]
        D -->|HTTP POST| E
    end

    subgraph ServerSide
        E -->|存储前| F[Base64Service.decode]
        F --> G[(数据库)]
        G -->|读取后| H[Base64Service.decode]
        H --> I[解码后数据]
    end

    style ClientSide fill:#e1f5fe
    style ServerSide fill:#f3e5f5
    style Transport fill:#fff3e0

编码服务实现

Base64Service 模块提供了简洁的编解码接口,应用于所有文本类型的存取操作:

module Base64Service
  def self.encode(text)
    return nil unless text
    Base64.encode64(text)
  end

  def self.decode(text)
    return nil unless text
    Base64.decode64(text)
  end
end

Sources: base64_service.rb

模型层自动编解码

Submission 模型通过自定义 getter/setter 方法,在数据存取层面透明地处理编码转换:

# 源码字段示例 - 其他字段模式相同
def source_code
  @decoded_source_code ||= Base64Service.decode(self[:source_code])
end

def source_code=(value)
  super(value)
  self[:source_code] = Base64Service.encode(self[:source_code])
end

此模式应用于以下字段:

  • source_code – 源代码内容
  • stdin – 标准输入数据
  • stdout – 标准输出结果
  • expected_output – 期望输出(用于比对)
  • stderr – 标准错误输出
  • compile_output – 编译输出信息

Sources: submission.rb

API 响应编码控制

序列化器支持通过 base64_encoded 参数控制响应格式:

def object_decoder(method)
  instance_options[:base64_encoded] ? object[method] : object.send(method)
end

当 base64_encoded=true 时,返回原始 Base64 编码数据;否则返回解码后的可读文本。

Sources: submission_serializer.rb

状态枚举与执行状态机

状态定义

Status 枚举定义了代码执行的完整状态集合:

ID 状态码 名称 含义
1 queue In Queue 等待处理
2 process Processing 正在执行
3 ac Accepted 执行成功且结果正确
4 wa Wrong Answer 结果不正确
5 tle Time Limit Exceeded 超出时间限制
6 ce Compilation Error 编译错误
7 sigsegv Runtime Error (SIGSEGV) 内存段错误
8 sigxfsz Runtime Error (SIGXFSZ) 文件大小超出限制
9 sigfpe Runtime Error (SIGFPE) 浮点运算错误
10 sigabrt Runtime Error (SIGABRT) 异常中止
11 nzec Runtime Error (NZEC) 非零退出码
12 other Runtime Error (Other) 其他运行时错误
13 boxerr Internal Error 沙箱内部错误
14 exeerr Exec Format Error 可执行文件格式错误

Sources: status.rb

状态转换逻辑

IsolateJob 中的 determine_status 方法根据 Isolate 沙箱返回的元数据确定最终状态:

def determine_status(status, exit_signal)
  case status
  when "TO" then Status.tle           # Time Limit Exceeded
  when "SG" then Status.find_runtime_error_by_status_code(exit_signal)
  when "RE" then Status.nzec          # Non Zero Exit Code
  when "XX" then Status.boxerr         # Internal Error
  else
    # 比较输出与期望输出
    if submission.expected_output.nil? || strip(expected_output) == strip(stdout)
      Status.ac
    else
      Status.wa
    end
  end
end

Sources: isolate_job.rb

执行配置参数

时间限制配置

参数 类型 默认值 最大值 说明
cpu_time_limit decimal 5.0 秒 15.0 秒 CPU 时间限制
cpu_extra_time decimal 1.0 秒 5.0 秒 额外缓冲时间
wall_time_limit decimal 10.0 秒 20.0 秒 墙上时间限制

Sources: config.rb

内存与存储限制

参数 类型 默认值 最大值 说明
memory_limit integer 128000 KB 512000 KB 内存限制
stack_limit integer 64000 KB 128000 KB 栈空间限制
max_file_size integer 1024 KB 4096 KB 最大文件大小
max_processes_and_or_threads integer 60 120 最大进程/线程数

Sources: config.rb

安全控制参数

参数 类型 默认值 说明
enable_per_process_and_thread_time_limit boolean false 启用进程级时间限制
enable_per_process_and_thread_memory_limit boolean false 启用进程级内存限制
redirect_stderr_to_stdout boolean false 将 stderr 重定向到 stdout
enable_network boolean false 启用网络访问
number_of_runs integer 1 执行次数

Sources: submission.rb, config.rb

Token 生成与唯一性保证

每个 Submission 通过 before_create 回调自动生成唯一 token:

before_create :generate_token

def generate_token
  self.token = SecureRandom.hex
end

Token 作为 API 访问的唯一标识符,存储在数据库中并建立了索引以确保查询性能:

t.index ["token"], name: "index_submissions_on_token"

Sources: submission.rb, schema.rb

生命周期时间戳

Submission 记录了完整的处理生命周期:

字段 说明
created_at 提交创建时间
queued_at 进入任务队列时间
started_at 开始执行时间
finished_at 执行完成时间
updated_at 最后更新时间
queue_host 接收提交的服务器
execution_host 执行提交的服务器

这些时间戳对于性能监控、队列分析和问题排查至关重要。

Sources: schema.rb

回调机制

当提交执行完成后,系统支持向指定的回调 URL 发送结果通知:

def call_callback
  return unless submission.callback_url.present?

  serialized_submission = ActiveModelSerializers::SerializableResource.new(
    submission,
    { serializer: SubmissionSerializer, base64_encoded: true }
  ).to_json

  Config::CALLBACKS_MAX_TRIES.times do
    begin
      HTTParty.put(submission.callback_url, body: serialized_submission)
      break
    rescue Exception
      # 重试逻辑
    end
  end
end

回调功能可通过环境变量 ENABLE_CALLBACKS=false 禁用,默认为启用状态。

Sources: isolate_job.rb, config.rb

完整执行流程

sequenceDiagram
    participant Client as 客户端
    participant API as SubmissionsController
    participant DB as 数据库
    participant Queue as IsolateRunner
    participant Sandbox as Isolate (沙箱)

    Client->>API: POST /submissions (Base64 编码)
    Note over API: Base64Service.decode() 解码
    API->>DB: Submission.create()
    DB-->>API: 返回 token
    API-->>Client: 返回 token

    alt 同步模式 (wait=true)
        API->>Queue: perform_now()
    else 异步模式
        API->>Queue: perform_later()
    end

    Queue->>Sandbox: 初始化沙箱环境
    Sandbox-->>Queue: box_id, workdir

    alt 需要编译
        Queue->>Sandbox: 执行 compile_cmd
        alt 编译成功
            Queue->>Sandbox: 执行 run_cmd
        else 编译失败
            Note over Queue: status = CE (Compilation Error)
        end
    else 解释型语言
        Queue->>Sandbox: 直接执行 run_cmd
    end

    Sandbox-->>Queue: metadata, stdout, stderr
    Queue->>Queue: determine_status() 判定状态

    alt 有回调 URL
        Queue->>Client: HTTP PUT callback_url
    end

    Queue->>DB: submission.save()
    Client->>API: GET /submissions/{token}
    API->>DB: 查询结果
    DB-->>API: Submission 数据
    API-->>Client: 返回结果 (Base64 可选)

Sources: submissions_controller.rb, isolate_job.rb

字段验证规则

Submission 模型实现了多层次的验证机制:

验证项 规则
source_code 存在性验证(非项目模式必须,项目模式禁止)
additional_files 项目模式必须存在
language_id 必须存在且未被归档
number_of_runs 1 ~ MAX_NUMBER_OF_RUNS (默认 20)
cpu_time_limit 0 ~ MAX_CPU_TIME_LIMIT (默认 15 秒)
memory_limit 2048 KB ~ MAX_MEMORY_LIMIT (默认 512000 KB)
compiler_options 长度 ≤ 512 字符
command_line_arguments 长度 ≤ 512 字符

Sources: submission.rb

序列化输出

SubmissionSerializer 定义了 API 响应的字段结构:

def self.default_fields
  @@default_fields ||= [
    :token, :time, :memory, :stdout, :stderr,
    :compile_output, :message, :status
  ]
end

默认响应包含执行结果的核心字段,完整字段列表可通过 fields 参数指定:

Sources: submission_serializer.rb


相关文档:

相关条目

  • 3-提交(Submission)核心概念
  • 11-创建提交 API
  • 10-Language 语言配置模型

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注