The hardware and bandwidth for this mirror is donated by dogado GmbH, the Webhosting and Full Service-Cloud Provider. Check out our Wordpress Tutorial.
If you wish to report a bug, or if you are interested in having us mirror your free-software or open-source project, please feel free to contact us at mirror[@]dogado.de.

Core Concepts and Architecture

Overview

SafeMapper achieves fault tolerance through three core mechanisms:

  1. Fingerprinting - Uniquely identifies each computational task
  2. Checkpointing - Periodically saves intermediate results
  3. Auto-Recovery - Seamlessly resumes interrupted tasks

This article provides an in-depth explanation of how these mechanisms work.

library(SafeMapper)

Architecture Overview

┌─────────────────────────────────────────────────────────────────────────────┐
│                        SafeMapper System Architecture                        │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│    User Code Layer                                                           │
│    ┌──────────────────────────────────────────────────────────────────┐     │
│    │  s_map()  s_map2()  s_pmap()  s_future_map()  s_walk()  ...      │     │
│    └─────────────────────────────┬────────────────────────────────────┘     │
│                                  │                                           │
│    Core Engine Layer             ▼                                           │
│    ┌──────────────────────────────────────────────────────────────────┐     │
│    │                    .safe_execute()                                │     │
│    │  ┌────────────┐  ┌────────────┐  ┌────────────┐  ┌────────────┐  │     │
│    │  │Fingerprint │  │ Checkpoint │  │   Batch    │  │   Error    │  │     │
│    │  │ Generator  │  │  Manager   │  │ Processor  │  │   Retry    │  │     │
│    │  └────────────┘  └────────────┘  └────────────┘  └────────────┘  │     │
│    └─────────────────────────────┬────────────────────────────────────┘     │
│                                  │                                           │
│    Storage Layer                 ▼                                           │
│    ┌──────────────────────────────────────────────────────────────────┐     │
│    │          R User Cache Directory (~/.cache/R/SafeMapper/)          │     │
│    │          └── checkpoints/                                         │     │
│    │              ├── session_abc123.rds                               │     │
│    │              └── session_def456.rds                               │     │
│    └──────────────────────────────────────────────────────────────────┘     │
│                                                                              │
└─────────────────────────────────────────────────────────────────────────────┘

1. Fingerprinting Mechanism

What is a Fingerprint?

A fingerprint is a unique identifier that identifies a specific computational task. SafeMapper automatically generates fingerprints by analyzing input data characteristics.

Fingerprint Generation Flow

┌─────────────────────────────────────────────────────────────────┐
│                    Fingerprint Generation                        │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│   Input Data                                                     │
│   [1, 2, 3, ..., 1000]                                          │
│          │                                                       │
│          ▼                                                       │
│   ┌─────────────────────────────────────────────┐               │
│   │            Extract Features                  │               │
│   │  ┌─────────────────────────────────────┐   │               │
│   │  │ mode:    "map"                      │   │               │
│   │  │ length:  1000                       │   │               │
│   │  │ class:   "numeric"                  │   │               │
│   │  │ first:   1                          │   │               │
│   │  │ last:    1000                       │   │               │
│   │  └─────────────────────────────────────┘   │               │
│   └───────────────────┬─────────────────────────┘               │
│                       │                                          │
│                       ▼                                          │
│   ┌─────────────────────────────────────────────┐               │
│   │         xxhash64 Hash Calculation            │               │
│   └───────────────────┬─────────────────────────┘               │
│                       │                                          │
│                       ▼                                          │
│   ┌─────────────────────────────────────────────┐               │
│   │    Fingerprint: "map_7a3b9c2d1e8f4a5b"      │               │
│   └─────────────────────────────────────────────┘               │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

Feature Selection Rationale

# These two calls will generate the same fingerprint
data <- 1:100

result1 <- s_map(data, ~ .x^2)
#> [1%] Processing items 1-100 of 100
#> Completed 100 items
# If re-run immediately, same fingerprint will be detected

# This call generates a different fingerprint (different data)
data2 <- 1:200
result2 <- s_map(data2, ~ .x^2)
#> [0%] Processing items 1-100 of 200
#> [50%] Processing items 101-200 of 200
#> Completed 200 items

Why not hash the entire dataset?

Custom Session IDs

For more precise control, you can manually specify a session ID:

# Use custom session ID
result <- s_map(1:20, ~ .x^2, .session_id = "my_custom_session")
#> [5%] Processing items 1-20 of 20
#> Completed 20 items

# This ensures that even tasks with similar data features won't conflict

2. Checkpointing Mechanism

Checkpoint Data Structure

┌─────────────────────────────────────────────────────────────────┐
│                    Checkpoint File Structure                     │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│   checkpoint_file.rds                                            │
│   │                                                              │
│   ├── results: list()                                            │
│   │   └── [1], [2], [3], ..., [completed items]                 │
│   │                                                              │
│   └── metadata: list()                                           │
│       ├── session_id:      "map_7a3b9c2d..."                    │
│       ├── total_items:     1000                                  │
│       ├── completed_items: 500                                   │
│       ├── mode:            "map"                                 │
│       ├── created:         "2026-01-23 10:30:00"                │
│       └── last_updated:    "2026-01-23 10:35:00"                │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

Checkpoint Save Timing

┌─────────────────────────────────────────────────────────────────┐
│                    Batch Processing & Checkpoints                │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│   Data: [1, 2, 3, ..., 1000]    Batch Size: 100                 │
│                                                                  │
│   ┌─────────────────────────────────────────────────────────┐   │
│   │  Batch 1: [1-100]                                        │   │
│   │     │                                                    │   │
│   │     ├── Complete ──────────► 💾 Save checkpoint (100)    │   │
│   │     ▼                                                    │   │
│   │  Batch 2: [101-200]                                      │   │
│   │     │                                                    │   │
│   │     ├── Complete ──────────► 💾 Save checkpoint (200)    │   │
│   │     ▼                                                    │   │
│   │  Batch 3: [201-300]                                      │   │
│   │     │                                                    │   │
│   │     └── ❌ INTERRUPTED!                                   │   │
│   │                                                          │   │
│   │  💾 Checkpoint saved: 200 items completed                │   │
│   └─────────────────────────────────────────────────────────┘   │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

Configuring Batch Size

# Default batch size is 100
# For fast operations, increase batch size to reduce I/O
s_configure(batch_size = 200)

# For slow operations (like API calls), decrease batch size for more frequent saves
s_configure(batch_size = 10)

# Reset to defaults
s_configure(batch_size = 100)

3. Auto-Recovery Mechanism

Recovery Flow

┌─────────────────────────────────────────────────────────────────┐
│                    Auto-Recovery Flow                            │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│   s_map(data, func) is called                                    │
│          │                                                       │
│          ▼                                                       │
│   ┌─────────────────────┐                                       │
│   │ Generate Fingerprint│                                       │
│   │ "map_7a3b9c2d..."   │                                       │
│   └──────────┬──────────┘                                       │
│              │                                                   │
│              ▼                                                   │
│   ┌─────────────────────┐         ┌─────────────────────┐       │
│   │ Checkpoint Exists?  │── Yes ─►│ Validate Checkpoint │       │
│   └──────────┬──────────┘         │ - Data length match?│       │
│              │                    │ - File not corrupt? │       │
│              │ No                 └──────────┬──────────┘       │
│              │                               │                   │
│              ▼                               │ Valid             │
│   ┌─────────────────────┐                   │                   │
│   │ Start Fresh         │                   ▼                   │
│   │ start_idx = 1       │         ┌─────────────────────┐       │
│   └──────────┬──────────┘         │ Resume Progress     │       │
│              │                    │ "Resuming from 200" │       │
│              │                    │ start_idx = 201     │       │
│              │                    └──────────┬──────────┘       │
│              │                               │                   │
│              └───────────────┬───────────────┘                   │
│                              │                                   │
│                              ▼                                   │
│                    ┌─────────────────────┐                      │
│                    │ Continue Batch      │                      │
│                    │ Processing          │                      │
│                    └──────────┬──────────┘                      │
│                               │                                  │
│                               ▼                                  │
│                    ┌─────────────────────┐                      │
│                    │ Delete Checkpoint   │                      │
│                    │ Return Results      │                      │
│                    └─────────────────────┘                      │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

Recovery Demo

# Simulate a task that might be interrupted
simulate_task <- function(x) {
  Sys.sleep(0.01)
  x^2
}

# First run
result <- s_map(1:30, simulate_task, .session_id = "recovery_demo")
#> [3%] Processing items 1-30 of 30
#> Completed 30 items

# If task is interrupted, simply re-run the same code:
# result <- s_map(1:30, simulate_task, .session_id = "recovery_demo")
# Output: "Resuming from item XX/30"

4. Error Retry Mechanism

Retry Flow

┌─────────────────────────────────────────────────────────────────┐
│                    Error Retry Mechanism                         │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│   Processing Batch [101-200]                                     │
│          │                                                       │
│          ▼                                                       │
│   ┌─────────────────────┐                                       │
│   │ Attempt 1           │                                       │
│   │ ❌ Error: Timeout    │                                       │
│   └──────────┬──────────┘                                       │
│              │                                                   │
│              ▼ Wait 1 second                                     │
│   ┌─────────────────────┐                                       │
│   │ Attempt 2           │                                       │
│   │ ❌ Error: Server Busy│                                       │
│   └──────────┬──────────┘                                       │
│              │                                                   │
│              ▼ Wait 1 second                                     │
│   ┌─────────────────────┐                                       │
│   │ Attempt 3           │                                       │
│   │ ✅ Success!          │                                       │
│   └──────────┬──────────┘                                       │
│              │                                                   │
│              ▼                                                   │
│   ┌─────────────────────┐                                       │
│   │ Save Checkpoint     │                                       │
│   │ Continue Next Batch │                                       │
│   └─────────────────────┘                                       │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

Configure Retry Attempts

# For unstable network environments, increase retry attempts
s_configure(retry_attempts = 5)

# For stable local computations, reduce retry attempts
s_configure(retry_attempts = 1)

# Reset to default
s_configure(retry_attempts = 3)

5. Storage Location

SafeMapper uses R’s standard user cache directory to store checkpoints:

# Checkpoint storage location (varies by system)
# Linux:   ~/.cache/R/SafeMapper/checkpoints/
# macOS:   ~/Library/Caches/org.R-project.R/R/SafeMapper/checkpoints/
# Windows: %LOCALAPPDATA%/R/cache/R/SafeMapper/checkpoints/

Complete Execution Flow

┌─────────────────────────────────────────────────────────────────────────────┐
│                    SafeMapper Complete Execution Flow                        │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│   ┌───────────────────────────────────────────────────────────────────┐     │
│   │                        User Invocation                             │     │
│   │              s_map(data, func, .session_id = NULL)                │     │
│   └───────────────────────────────┬───────────────────────────────────┘     │
│                                   │                                          │
│                                   ▼                                          │
│   ┌───────────────────────────────────────────────────────────────────┐     │
│   │  1. Generate Fingerprint                                           │     │
│   │     session_id = .make_fingerprint(data, "map")                   │     │
│   └───────────────────────────────┬───────────────────────────────────┘     │
│                                   │                                          │
│                                   ▼                                          │
│   ┌───────────────────────────────────────────────────────────────────┐     │
│   │  2. Try Recovery                                                   │     │
│   │     restored = .try_restore(session_id, length(data))             │     │
│   │     ├── Has checkpoint ──► results = restored$results             │     │
│   │     │                      start_idx = completed_items + 1        │     │
│   │     └── No checkpoint ───► results = vector("list", n)            │     │
│   │                            start_idx = 1                           │     │
│   └───────────────────────────────┬───────────────────────────────────┘     │
│                                   │                                          │
│                                   ▼                                          │
│   ┌───────────────────────────────────────────────────────────────────┐     │
│   │  3. Batch Processing Loop                                          │     │
│   │     for batch in batches(start_idx:n):                            │     │
│   │         │                                                          │     │
│   │         ├── Show progress: "[XX%] Processing items X-Y of N"      │     │
│   │         │                                                          │     │
│   │         ├── Execute batch (with retry)                            │     │
│   │         │   batch_results = .execute_batch_with_retry(...)        │     │
│   │         │                                                          │     │
│   │         ├── Store results                                          │     │
│   │         │   results[batch_indices] = batch_results                │     │
│   │         │                                                          │     │
│   │         └── Save checkpoint                                        │     │
│   │             .save_checkpoint(session_id, results, ...)            │     │
│   └───────────────────────────────┬───────────────────────────────────┘     │
│                                   │                                          │
│                                   ▼                                          │
│   ┌───────────────────────────────────────────────────────────────────┐     │
│   │  4. Completion                                                     │     │
│   │     .cleanup_checkpoint(session_id)  # Delete checkpoint          │     │
│   │     message("Completed N items")                                   │     │
│   │     return(.format_output(results, output_type))                  │     │
│   └───────────────────────────────────────────────────────────────────┘     │
│                                                                              │
└─────────────────────────────────────────────────────────────────────────────┘

Design Principles

SafeMapper follows these design principles:

┌─────────────────────────────────────────────────────────────────┐
│                    Design Principles                             │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  1. Zero Configuration First                                     │
│     ├── Works out of the box, no setup required                 │
│     └── All configuration is optional                           │
│                                                                  │
│  2. Non-Invasive                                                 │
│     ├── API fully compatible with purrr/furrr                   │
│     ├── Just change function name, no code restructuring        │
│     └── Can switch back to native purrr anytime                 │
│                                                                  │
│  3. Transparent Operation                                        │
│     ├── Checkpoints managed automatically                       │
│     ├── Users don't need to worry about details                 │
│     └── Automatic cleanup after success                         │
│                                                                  │
│  4. Safe and Reliable                                            │
│     ├── Save per batch, minimize data loss                      │
│     ├── Automatic error retry                                   │
│     └── Corrupted checkpoints safely ignored                    │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

Next Steps

These binaries (installable software) and packages are in development.
They may not be fully stable and should be used with caution. We make no claims about them.
Health stats visible at Monitor.