IT Support & Help Desk Fundamentals Module 11 – Backups, recovery and data disposal
Backup strategy: 3-2-1, versions and restore tests
Choose a backup type, rotation and offline copy, write RPO and RTO numbers from a worked example, and prove the plan with a restore test.
What you will learn
- Compare full, incremental, differential and synthetic full backup kinds by storage, restore chain and backup window
- Plan a 3-2-1 schedule with an offline or immutable copy and a documented retention policy
- Compute an RPO and an RTO from a schedule, a data size and a throughput
- Explain why file sync and RAID are not backups, with the deletion rule each one breaks
- Design a restore test that proves a backup can bring the right data back
Before you start
What you’ll learn · Before you start
What you will learn
- Compare full, incremental, differential and synthetic full backup kinds by storage, restore chain and backup window
- Plan a 3-2-1 schedule with an offline or immutable copy and a documented retention policy
- Compute an RPO and an RTO from a schedule, a data size and a throughput
- Explain why file sync and RAID are not backups, with the deletion rule each one breaks
- Design a restore test that proves a backup can bring the right data back
Before you start
On this page
A drive fails at 15:42 on a Tuesday. A nightly backup ran 13 hours 42 minutes ago, so 822 minutes of work could be gone. A plan with a backup every 4 hours would have cut that to 102 minutes. The right question is not “do we have backups?” but “how old is the newest copy, and how fast can we restore it?”
This lesson gives you the numbers. You will compare four backup kinds, lay out a 3-2-1 schedule with an offline or immutable copy, work out an RPO and an RTO for a real failure, see why sync and RAID are not backups, and plan a restore test that proves the plan. Platform tools are in backup tools by platform; getting data back after a failure is in restore and data recovery.
Four kinds of backup, four trade-offs
Every backup chooses what to copy and how to find it later. The four kinds that nearly every tool supports are full, incremental, differential and synthetic full. They differ in the backup window, the storage used and how many files a restore has to read.
A full backup: A backup that copies every file in scope on every run. It is the simplest kind to restore, because one copy holds everything, but it takes the most storage and the longest backup window. copies every file in scope every time it runs. A full copy of 480 GB over a 100 Mbit/s link takes 10.7 hours of copy time, so a full every night is heavy. On the other hand, a restore reads one copy and is done.
An incremental backup: A backup that copies only the files changed since the last backup of any kind. The run is small and quick, but a restore reads the last full copy and every incremental after it, in order. copies only the files changed since the last backup, of any kind. The nightly run is small, but a restore reads the last full copy plus every incremental since then, in order. The chain grows every day until the next full.
A differential backup: A backup that copies every file changed since the last full backup. Each differential run is larger than the one before, but a restore reads only two things: the last full plus the last differential. copies every file changed since the last full backup, not since the last run. Each differential run is larger than the one before, but a restore reads two things: the last full and the latest differential.
A synthetic full backup: A full copy that the backup server builds from the last full backup and every incremental since it, without reading the live source again. The restore side sees a full copy, so there is no incremental chain to replay. is built on the backup server, not read fresh from the source. The server takes the last full copy and every incremental, and stitches them into a new full copy. The source network sees only the incremental; the restore side sees a one-step full copy.
Answer the questions above: the table then marks what fits your case and says why the rest does not.
| Backup kind | Backup window | Storage per run | Restore steps |
|---|---|---|---|
| Full Reads from the source: every file in scope | Poor every byte travels: 480 GB at 100 Mbit/s is 10.7 hours of copy | Poor a whole new copy every run | Good one step: read the one copy |
| Incremental Reads from the source: changes since the last run | Good the shortest: one run of changes | Good the smallest: each change is stored once | Poor the last full, then every incremental since, in order |
| Differential Reads from the source: changes since the last full | Mixed grows each night until the next full | Mixed each run stores every change since the full again | Good two steps: the last full and the latest differential |
| Synthetic full Reads from the source: the same as an incremental | Good as short as an incremental | Poor the server stores a new full copy each time | Good one step: the restore side sees a full copy |
How the answers decide
- “How soon must a whole restore be finished?” Within a few hours: rules out Incremental. A restore reads the last full and then every incremental since, in order: the longest chain, and one bad link stops it.
- “How often does a backup run?” Several times a day: rules out Full. A full copy every run takes the longest window: 480 GB over 100 Mbit/s is 10.7 hours, too long to repeat several times a day.
- “How often does a backup run?” Several times a day: adds a caveat to Differential. Each run copies every change since the last full again, so the runs grow longer through the week.
- “How often does a backup run?” Once a night: adds a caveat to Full. At 480 GB over 100 Mbit/s a full copy takes 10.7 hours, longer than most nights; it fits a smaller data set or a faster link.
- “How much room does the backup storage have?” Tight, one small disk: rules out Full and Synthetic full. Both store a whole new copy each time, a full read from the source or a synthetic one built on the server, and a tight budget holds few of them.
Three questions about your plan decide most of the choice. In short: a fast restore target rules out the long incremental chain, several runs a day rule out a full copy each time, and a tight storage budget rules out both kinds that store a new full copy, plain or synthetic. A nightly plan with a fast restore and room to spare is left with synthetic full, differential, and a full copy only if the data fits the night.
Key idea
The storage cost falls with incremental, the restore chain grows with incremental, and synthetic full gives both a short backup window and a one-step restore - at the cost of the storage a new full takes.
Checkpoint
Check: Full, incremental, differential and synthetic full
3-2-1, and one copy offline or immutable
A single copy on the same drive is no backup: the drive is one failure away from losing both. The 3-2-1 rule: A planning rule of thumb for backups: keep 3 copies of the data, on at least 2 different kinds of media, with 1 copy stored offsite or offline. Current ransomware guidance adds that one copy is offline or immutable. is a planning minimum: three copies of the data, on two different kinds of media, with one copy stored offsite or offline.
Current ransomware guidance tightens the third copy. The #StopRansomware Guide of CISA, the United States cyber defence agency, asks for offline, encrypted backups of critical data that are tested regularly, for availability and integrity, as if in a disaster. It also warns that many ransomware variants hunt for the backups they can reach and delete or encrypt them. A copy that is always on the network is at risk from the same attack that broke the live system.
Two patterns answer that. An offline backup: A backup copy kept on a device that is disconnected from the production network between runs, so that malware on a live machine cannot reach it. CISA's #StopRansomware Guide asks for offline, encrypted, tested backups. is written to a device that is disconnected between runs: a tape rotated out of a safe, a hard drive carried to another building, a cloud account that nothing on the live network has credentials for. An immutable backup: A backup stored so the data cannot be changed or deleted before a set date, usually through write-once-read-many media or an object store with object-lock turned on. It gives the same effect as offline media against a live attack. is written to storage that refuses deletions and overwrites before a set date, such as an object store with object-lock turned on. Both give the same guarantee: the day’s attacker cannot reach the day’s backup.
A small-office 3-2-1 that fits a tight budget
Three copies: the live drive, a USB disk plugged in nightly, and a cloud account on a provider’s starter plan with versioning turned on. Two media: local disk and cloud. One offline: the USB disk is unplugged after the backup, so a ransomware infection does not reach it.
A small table maps that callout to each part of the rule, so every number in it points at something real:
| Part of 3-2-1 | What the small office uses |
|---|---|
| 3 copies of the data | Live drive, nightly USB disk, cloud account |
| 2 kinds of media | Local disk and cloud storage |
| 1 copy offline or immutable | USB disk unplugged between runs |
Checkpoint
Check: 3-2-1 and an offline or immutable copy
Rotation: what you keep today, this week, this year
A plan that keeps only the newest copy loses the data to the first infected run. A rotation keeps a mix of recent and older copies, so a corruption found late can still be rolled back. The grandfather-father-son: A rotation that keeps three tiers of copies: a daily one for the last 7 days, a weekly one for the last few Sundays and a monthly one for the first of the last 12 months. Clashing dates keep the shorter tier. rotation (GFS) is a common choice: a daily copy for the last 7 days, a weekly copy for the last 4 weeks (Sundays, say), and a monthly copy for the first of each of the last 12 months.
Apple documents Time Machine’s rule in a different shape. Support article 104984 says Time Machine keeps a point for every hour over the last day, a point for every day over the last month, and one point a week for the months before that; the oldest points are dropped as the disk fills. Apple also advises a storage device with at least twice the Mac’s capacity, so the history has room before the oldest points begin to go.
The program below runs both rules on a fixed Wednesday afternoon and prints the restore points each keeps:
"""Which restore points still exist on a given date, for two backup schedules.
Two schedules are modelled on fixed dates (never today's date):
- Grandfather-father-son (GFS): a daily copy for the last 7 days, a weekly copy
for the last 4 weeks, a monthly copy for the last 12 months.
- Time Machine's documented rule (Apple support 104984): hourly copies for the
past 24 hours, daily copies for the past month, weekly copies for all previous
months. The disk itself is finite, and the oldest copies are deleted when it
is full; this program does not model the disk's capacity.
Nothing is random; two runs print the same text.
"""
from datetime import date, datetime, timedelta, timezone
IST = timezone(timedelta(hours=5, minutes=30))
TODAY = date(2026, 4, 15) # a fixed Wednesday
FAILURE = datetime(2026, 4, 15, 14, 30, tzinfo=IST) # office-hour failure
def gfs_points(on_date: date) -> list[tuple[str, date]]:
"""Returns the restore points a grandfather-father-son schedule keeps.
The schedule runs a backup every day: the last 7 become daily copies, every
Sunday of the last 4 weeks is kept as the week's copy, and the first day of
the last 12 months is kept as that month's copy.
"""
points: list[tuple[str, date]] = []
for i in range(1, 8):
points.append(("daily", on_date - timedelta(days=i)))
for i in range(1, 5):
last_sunday = on_date - timedelta(days=on_date.weekday() + 1 + 7 * (i - 1))
points.append(("weekly", last_sunday))
year, month = on_date.year, on_date.month
for i in range(1, 13):
month -= 1
if month == 0:
month = 12
year -= 1
points.append(("monthly", date(year, month, 1)))
seen: set[date] = set()
unique: list[tuple[str, date]] = []
for kind, d in sorted(points, key=lambda p: p[1], reverse=True):
if d not in seen:
seen.add(d)
unique.append((kind, d))
return unique
def time_machine_points(now: datetime) -> list[tuple[str, datetime]]:
"""Returns the restore points Time Machine keeps under its documented rule.
One hourly copy for every past hour in the last 24, one daily copy for every
past day in the last month, one weekly copy for every earlier week. The
program keeps a year of weekly copies, which is far short of a Mac user's
real disk; the oldest copies are deleted when the disk fills.
"""
points: list[tuple[str, datetime]] = []
hour = now.replace(minute=0, second=0, microsecond=0)
for i in range(1, 25):
points.append(("hourly", hour - timedelta(hours=i)))
midnight = now.replace(hour=0, minute=0, second=0, microsecond=0)
for i in range(1, 32):
points.append(("daily", midnight - timedelta(days=i)))
first_weekly = midnight - timedelta(days=31)
first_weekly = first_weekly - timedelta(days=first_weekly.weekday())
for i in range(1, 53):
points.append(("weekly", first_weekly - timedelta(weeks=i - 1)))
return sorted(points, key=lambda p: p[1], reverse=True)
def summary(name: str, kept: list[tuple[str, object]]) -> None:
counts: dict[str, int] = {}
for kind, _ in kept:
counts[kind] = counts.get(kind, 0) + 1
oldest = kept[-1][1]
print(f"{name}: {len(kept)} restore points kept.")
for kind in sorted(counts):
print(f" {kind:>8}: {counts[kind]}")
print(f" oldest : {oldest}")
print()
print("Backup rotation on a fixed date (2026-04-15, Wednesday).")
print("=" * 60)
print()
gfs = gfs_points(TODAY)
summary("Grandfather-father-son", gfs)
print("First 8 restore points of the GFS schedule, newest first:")
for kind, d in gfs[:8]:
print(f" {d.isoformat()} ({d.strftime('%a')}) - {kind}")
print()
tm = time_machine_points(FAILURE)
summary("Time Machine (hourly + daily + weekly)", tm)
print("First 6 restore points of Time Machine, newest first:")
for kind, when in tm[:6]:
print(f" {when.strftime('%Y-%m-%d %H:%M %z')} - {kind}")
print()
print("A failure on this Wednesday afternoon has these recent options.")
same_day = [p for p in tm if p[1].date() == FAILURE.date() and p[1] <= FAILURE]
if same_day:
newest = max(same_day, key=lambda p: p[1])
data_lost = (FAILURE - newest[1]).total_seconds() / 60
print(f"Newest Time Machine point before the failure: {newest[1].strftime('%H:%M')}")
print(f"Data at risk since that point: {int(data_lost)} minutes of work.") Output
Backup rotation on a fixed date (2026-04-15, Wednesday).
============================================================
Grandfather-father-son: 22 restore points kept.
daily: 7
monthly: 12
weekly: 3
oldest : 2025-04-01
First 8 restore points of the GFS schedule, newest first:
2026-04-14 (Tue) - daily
2026-04-13 (Mon) - daily
2026-04-12 (Sun) - daily
2026-04-11 (Sat) - daily
2026-04-10 (Fri) - daily
2026-04-09 (Thu) - daily
2026-04-08 (Wed) - daily
2026-04-05 (Sun) - weekly
Time Machine (hourly + daily + weekly): 107 restore points kept.
daily: 31
hourly: 24
weekly: 52
oldest : 2025-03-17 00:00:00+05:30
First 6 restore points of Time Machine, newest first:
2026-04-15 13:00 +0530 - hourly
2026-04-15 12:00 +0530 - hourly
2026-04-15 11:00 +0530 - hourly
2026-04-15 10:00 +0530 - hourly
2026-04-15 09:00 +0530 - hourly
2026-04-15 08:00 +0530 - hourly
A failure on this Wednesday afternoon has these recent options.
Newest Time Machine point before the failure: 13:00
Data at risk since that point: 90 minutes of work.
Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 rotation.py
Runs on this device, in your browser. The first run downloads Python (about 13.5 MB), which is kept for the next runs.
Your run, in this browser
GFS keeps 22 restore points on that date: 7 daily, 3 weekly (one Sunday is already a daily copy, so only 3 Sundays stay as weekly), and 12 monthly points reaching back a year. Time Machine keeps 107: 24 hourly, 31 daily and 52 weekly, with the oldest point just over a year earlier.
The drawing shows the whole scene; its 5 steps are listed below.
Every step as text
- Start with the live data. The file server, Mac or laptop that users work on. One copy, no history yet.
- Keep seven daily copies. Every night a daily copy is written. On the Wednesday the example models, the 7 daily points are the preceding Tuesday back to the Wednesday a week earlier, covering the last working week.
- Keep weekly copies on Sundays. Each Sunday a copy is kept and labelled weekly. For a Wednesday the Sunday 3 days earlier is already in the daily tier, so only 3 of the 4 Sundays stay labelled weekly, the oldest about four weeks back.
- Keep a monthly copy per month. On the first day of every month a monthly copy is kept. The example keeps 12 of them, from the first of the month before the current one back twelve months. Together there are 7 daily + 3 weekly + 12 monthly = 22 restore points.
- Rotate the oldest copy offline. Once a month, carry an older monthly copy out of the building or write it to immutable storage. The CISA ransomware guide asks for offline backups, so a copy on a shelf or in a cloud bucket with object-lock turns the schedule into one that survives an attack on the live site.
A retention policy: A written rule for how long each kind of backup copy is kept and when it is deleted. It balances the time a user has to notice a loss, the storage cost and the time to find a given file in the history. ties the rotation to a written rule: a user who notices a wrong save a month later can still roll back to the first of that month; a legal hold that asks for a year of history is covered by the monthly tier. Choose the dates by what the business needs to find, not by the disk you happen to have.
Checkpoint
Check: Rotation and retention tiers
RPO and RTO: numbers the business agrees
Two numbers describe how a plan behaves at a failure. The recovery point objective (RPO): The oldest change a backup plan accepts to lose when the system fails. A nightly backup gives an RPO of one day; a backup every 4 hours gives an RPO of 4 hours. A shorter RPO costs more storage and bandwidth. (RPO) is the oldest change the plan accepts to lose. The recovery time objective (RTO): The longest time a business accepts to stay down before data and services are back. It covers finding the backup, mounting it, restoring the data and testing that users can work again, not only the copy time. (RTO) is the longest time the plan accepts to stay down before everything is back.
RPO is set by the schedule: a nightly backup gives an RPO of one day; a backup every 4 hours gives an RPO of 4 hours. On average, half the gap is lost; at the worst case, the full gap. RTO is set by the restore: the time to locate the backup, mount it, copy the data, and prove the users are back.
"""Worked numbers for a backup plan: RPO (what is lost) and RTO (how long to come back).
RPO = recovery point objective: the oldest change a plan accepts to lose when
the system fails. If a backup runs every N hours, a failure that happens
anywhere in that gap loses up to N hours of work; on average, N/2.
RTO = recovery time objective: how long the business accepts to stay down
before everything is back. For a restore that reads data from one place to
another, the time taken is roughly data_size / throughput, plus a fixed
amount for the first steps (locate the backup, mount it, start the restore).
Numbers are fixed in the program; two runs print the same text.
"""
from datetime import datetime, timedelta, timezone
IST = timezone(timedelta(hours=5, minutes=30))
# Two schedules, each named by its gap between backups.
schedules = [
("Nightly backup at 02:00", timedelta(hours=24)),
("Every 4 hours (02, 06, 10, 14, 18, 22)", timedelta(hours=4)),
]
# A failure happens at this fixed moment on a Tuesday afternoon.
failure = datetime(2026, 5, 12, 15, 42, tzinfo=IST)
def last_backup_before(failure_time: datetime, gap: timedelta, anchor_hour: int) -> datetime:
"""Returns the most recent backup finish time at or before failure_time.
Backups finish at anchor_hour, anchor_hour + gap, anchor_hour + 2*gap and so
on. We start on the failure's own date at anchor_hour, roll forward in
steps of gap while we are still at or before the failure, then step back
once to get the last finished backup.
"""
anchor = failure_time.replace(hour=anchor_hour, minute=0, second=0, microsecond=0)
if anchor > failure_time:
anchor -= timedelta(days=1)
while anchor + gap <= failure_time:
anchor += gap
return anchor
print("RPO: how much data could you lose?")
print("=" * 60)
print(f"Failure: {failure.strftime('%Y-%m-%d %H:%M %z')} (Tuesday afternoon)")
print()
rows = []
for name, gap in schedules:
anchor_hour = 2 if gap == timedelta(hours=24) else 6
last = last_backup_before(failure, gap, anchor_hour)
lost = failure - last
rows.append((name, gap, last, lost))
minutes = int(lost.total_seconds() // 60)
print(f"{name}")
print(f" Last backup before the failure : {last.strftime('%Y-%m-%d %H:%M')}")
print(f" Data lost at the failure : {minutes} minutes "
f"({minutes / 60:.1f} hours)")
print(f" Worst case (just before next) : {int(gap.total_seconds() // 60)} minutes")
print()
print("RTO: how long to come back?")
print("=" * 60)
# A customer's share: 480 GB of files on a laptop that has to be re-imaged.
# Three network speeds are shown: a home fibre line, an office gigabit link,
# and a cold cloud restore that is throttled.
data_gb = 480
plans = [
("Home fibre line, 100 Mbit/s download", 100),
("Office LAN, 1 Gbit/s (effective 800 Mbit/s)", 800),
("Cold cloud restore, 25 Mbit/s", 25),
]
first_steps_minutes = 20 # locate the backup, start the restore
print(f"Data to restore: {data_gb} GB (one laptop's work drive)")
print(f"First steps (locate, start): {first_steps_minutes} minutes")
print()
for name, mbps in plans:
seconds = (data_gb * 8 * 1000) / mbps # GB -> Gbit -> seconds at Mbit/s
minutes = seconds / 60
total = first_steps_minutes + minutes
hours = total / 60
print(f"{name}")
print(f" Transfer time : {minutes:,.0f} minutes "
f"({seconds / 3600:.1f} hours of pure copy)")
print(f" Full RTO estimate : {total:,.0f} minutes "
f"(about {hours:.1f} hours)")
print()
print("Note: 1 GB is written as 1,000,000,000 bytes here, as drive makers count,")
print("and 1 Mbit/s as 1,000,000 bits a second, so 100 Mbit/s is 12.5 MB/s.") Output
RPO: how much data could you lose? ============================================================ Failure: 2026-05-12 15:42 +0530 (Tuesday afternoon) Nightly backup at 02:00 Last backup before the failure : 2026-05-12 02:00 Data lost at the failure : 822 minutes (13.7 hours) Worst case (just before next) : 1440 minutes Every 4 hours (02, 06, 10, 14, 18, 22) Last backup before the failure : 2026-05-12 14:00 Data lost at the failure : 102 minutes (1.7 hours) Worst case (just before next) : 240 minutes RTO: how long to come back? ============================================================ Data to restore: 480 GB (one laptop's work drive) First steps (locate, start): 20 minutes Home fibre line, 100 Mbit/s download Transfer time : 640 minutes (10.7 hours of pure copy) Full RTO estimate : 660 minutes (about 11.0 hours) Office LAN, 1 Gbit/s (effective 800 Mbit/s) Transfer time : 80 minutes (1.3 hours of pure copy) Full RTO estimate : 100 minutes (about 1.7 hours) Cold cloud restore, 25 Mbit/s Transfer time : 2,560 minutes (42.7 hours of pure copy) Full RTO estimate : 2,580 minutes (about 43.0 hours) Note: 1 GB is written as 1,000,000,000 bytes here, as drive makers count, and 1 Mbit/s as 1,000,000 bits a second, so 100 Mbit/s is 12.5 MB/s.
Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 rpo_rto.py
Runs on this device, in your browser. The first run downloads Python (about 13.5 MB), which is kept for the next runs.
Your run, in this browser
The program prints the exact numbers for a Tuesday afternoon failure modelled in the example. The nightly plan lost 822 minutes of work (13.7 hours); the 4-hour plan lost 102 minutes (1.7 hours). For an RTO of restoring 480 GB, the three throughputs the program tries give 11 hours over a 100 Mbit/s home line, 1.7 hours over an 800 Mbit/s office LAN, and 43 hours over a 25 Mbit/s cold cloud restore. The exact arithmetic is in the program; the download time calculator will work out other sizes and speeds.
The drawing shows the whole scene; its 6 steps are listed below.
Every step as text
- Last night at 02:00. The nightly job finished and copied the day's work to the backup disk and to an offsite copy. The RPO this plan accepts is one day, so an outage any time between runs could lose up to one day of work.
- Tuesday morning, 09:00. Users sign in and start editing files. Nothing is backed up again until the night. Any file saved now is at risk until the next scheduled run.
- Tuesday afternoon, 15:00. Many files were saved; one order was taken on the phone and a spreadsheet was updated with the figure. All of it sits only on the live drive and the live file server.
- Drive fails at 15:42. The failure is 13 hours 42 minutes after the last backup. The rpo_rto.py example prints 822 minutes - the exact gap for this plan.
- Restore starts. A technician locates the backup, mounts it, and starts the copy to a replacement drive. These first steps are costed as 20 minutes in the example, before any data moves.
- Users back on. On a 100 Mbit/s home line a 480 GB restore takes about 640 minutes of pure copy; adding 20 minutes of setup gives a full RTO of about 11 hours. A faster link or local disk cuts it to about 100 minutes.
Both numbers are agreed with the business, not chosen by IT. An office that cannot run for 8 hours needs a plan that restores in 4; a studio that saves work every 15 minutes needs an RPO under an hour. A plan with no agreed numbers always surprises somebody when a failure comes.
Checkpoint
Check: RPO and RTO from a schedule and a restore
File sync is not a backup, and nor is RAID
Two tools look like backups and are not. The first is a file sync service: OneDrive, iCloud Drive, Google Drive, Dropbox. These keep a copy of a folder on another device or in a cloud, so a drive failure does not lose the files. But a delete is also synced: when a user removes a folder on the laptop, the service removes it on every device. The copy that was supposed to save you is gone within seconds.
File sync services soften the blow with recycle bins and version histories. Microsoft’s OneDrive documentation sets the window at 30 days for personal accounts and 93 days for work or school accounts, and an administrator can change the second. After that window the deleted files are gone, so a loss noticed later has nothing left to restore.
The second is RAID. Storage drives and RAID covered the levels; the key point here is that RAID mirrors every write to the array. A delete, an encryption, a wrong save - every one is written to every member disk. RAID keeps a service running when a single disk dies; it does not keep an earlier state of the data.
Treating a cloud folder or RAID as the backup
Wrong: “The user’s files are in OneDrive, so there is no need for a backup.” Right: a sync service is one copy with a 30-day or 93-day recycle bin; a loss noticed on day 95 is unrecoverable. A separate, versioned, offline or immutable backup covers that gap.
A short table lines up what each tool handles against what a versioned backup handles:
| What goes wrong | File sync | RAID 1 | Versioned backup |
|---|---|---|---|
| One disk dies | Covered on another device | Covered by the mirror | Covered by the latest copy |
| A delete noticed within days | Recycle bin for 30 or 93 days | Lost (write mirrored) | Any version within retention |
| Ransomware or a wrong save | Change synced to every copy | Change written to every disk | Offline or immutable copy survives |
Checkpoint
Check: Why sync and RAID are not backups
A backup counts only after a restore test
A backup only exists if a restore from it works. A plan that runs every night for a year, that passes every integrity check, and that nobody has ever restored from, is a plan with an unknown RTO and a possibly broken index. The restore test: A rehearsed restore from a backup copy to a scratch target, checked against the live data by file counts, hashes or a user's spot checks. Only a restore that was tested is proven to work; untested backups fail at the worst time. is the step that turns a plan into something you can rely on.
CISA’s guidance asks for backups to be tested regularly, for availability and integrity, as a disaster would test them. The test does not have to be a full disaster rehearsal. A smaller rehearsal, repeated on a schedule, is enough:
- Pick a target - a file, a folder or a whole volume - from a recent backup.
- Restore it to a scratch location, never over the live data.
- Compare the restored data with the live copy by file counts and by hashes (the hash generator will do a SHA-256 of a file in the browser).
- Have a user who knows the files open two or three of them, so a corruption that no hash catches still turns up.
- Record the date, the data checked and the RTO of the test, in the ticket system.
Each check in that list catches a different kind of failure, so dropping one leaves a quiet hole in the plan:
| Check in the test | What it catches |
|---|---|
| File count | Index gaps and files the backup missed |
| SHA-256 of each restored file | Bit-level corruption in storage or in transit |
| User opens two or three files | Format or link breaks that no hash catches |
Run the test often enough that a change in the plan - a new tool, a new disk, a new cloud account - is tested before it is relied on. In practice: once a month is a reasonable floor for a small office; a critical system should test weekly.
Checkpoint
Check: The restore test
Practise
Write a function that lists the restore points a schedule keeps on a given date. The tests check the 22 points of the GFS example and the Sundays and firsts of the month they fall on, a month-end date, the 83 points of the exercise’s simplified Time Machine rule and its newest weekly Monday, that no point lies after the date, and an unknown schedule name.
Exercise · Easy · Python
List the restore points a schedule keeps
List the restore points a backup schedule keeps for a given date.
Write a function restore_points(schedule, on_date) that takes:
schedule: one of"gfs"(grandfather-father-son) or"time-machine".on_date: adatetime.dateto list the points as if the time were midnight on that date.
The function returns a list of (kind, date) tuples, newest first.
For "gfs" (daily for the last 7 days, weekly for the last 4 weeks (Sundays), monthly for the last 12 months (first of the month)):
- 7 daily points, one for each of the 7 days before
on_date. - 4 weekly points, the last 4 Sundays before
on_date. - 12 monthly points, the first of each of the 12 months before
on_date's month. - When a weekly or monthly date clashes with a daily or weekly date already in the list, keep the earlier kind (
dailywins overweekly,weeklywins overmonthly) and drop the later duplicate.
For "time-machine" (Apple's hourly, daily and weekly rule, simplified here to whole days, so the hourly points of the current day count as one daily point):
- 31 daily points:
on_dateitself and each of the 30 days before it. - 52 weekly points, all Mondays: the Monday on or before the date 31 days before
on_date, then each of the 51 Mondays before that one.
Sort the 83 points newest first.
For an invalid schedule or on_date not a date, return {"error": "<message>"}.
Example:
from datetime import date
points = restore_points("gfs", date(2026, 4, 15))
# points[0] == ("daily", date(2026, 4, 14))
# len(points) == 22Starter code · restore_points.py
from datetime import date, timedelta
def restore_points(schedule: str, on_date):
"""Return (kind, date) tuples the given schedule keeps for the given date.
Args:
schedule: 'gfs' or 'time-machine'.
on_date: a datetime.date giving the day to list the restore points for.
Returns:
A list of (kind, date) tuples, newest first, or a dict {'error': ...}
for invalid input.
"""
# Your code here
return [] The sample tests · test_restore_points.py
"""Sample tests for restore_points. Run: python test_restore_points.py"""
from datetime import date
from restore_points import restore_points
def test_gfs_total():
points = restore_points("gfs", date(2026, 4, 15))
assert len(points) == 22, f"GFS on 2026-04-15 should keep 22 points, got {len(points)}"
def test_gfs_weekly_sundays():
# Sunday 12 April is already a daily point, so 3 Sundays stay weekly.
points = restore_points("gfs", date(2026, 4, 15))
weekly = [d for k, d in points if k == "weekly"]
expected = [date(2026, 4, 5), date(2026, 3, 29), date(2026, 3, 22)]
assert weekly == expected, f"weekly points should be the Sundays 5 April, 29 March and 22 March, got {weekly}"
def test_gfs_monthly_firsts():
points = restore_points("gfs", date(2026, 4, 15))
monthly = [d for k, d in points if k == "monthly"]
assert len(monthly) == 12, f"GFS should keep 12 monthly points, got {len(monthly)}"
assert monthly[0] == date(2026, 3, 1) and monthly[-1] == date(2025, 4, 1), (
f"monthly points should run from 2026-03-01 back to 2025-04-01, got {monthly[0]} to {monthly[-1]}"
)
def test_gfs_month_end():
# On the last day of April, the 7 daily points run from 23 to 29 April.
points = restore_points("gfs", date(2026, 4, 30))
daily = [d for k, d in points if k == "daily"]
assert daily[0] == date(2026, 4, 29), f"newest daily should be 29 April, got {daily[0]}"
assert daily[-1] == date(2026, 4, 23), f"oldest daily should be 23 April, got {daily[-1]}"
def test_no_point_after_the_date():
on = date(2026, 4, 15)
for schedule in ("gfs", "time-machine"):
points = restore_points(schedule, on)
assert points, f"{schedule}: should return restore points, got none"
late = [d for k, d in points if d > on]
assert not late, f"{schedule}: no restore point can be after {on}, got {late[:3]}"
def test_time_machine_count():
# 1 current + 30 past days + 52 weekly = 83 points.
points = restore_points("time-machine", date(2026, 4, 15))
assert len(points) == 83, f"Time Machine should keep 83 points, got {len(points)}"
def test_time_machine_newest_weekly():
# 31 days before 15 April is Sunday 15 March; the Monday on or before it is 9 March.
points = restore_points("time-machine", date(2026, 4, 15))
weekly = [d for k, d in points if k == "weekly"]
assert weekly and weekly[0] == date(2026, 3, 9), f"newest weekly point should be Monday 9 March, got {weekly[:1]}"
def test_time_machine_oldest_point():
# The oldest of the 83 points is the last of the 52 weekly Mondays.
points = restore_points("time-machine", date(2026, 4, 15))
oldest_kind, oldest_date = points[-1]
assert oldest_kind == "weekly", f"oldest point should be weekly, got {oldest_kind}"
assert oldest_date.weekday() == 0, (
f"oldest weekly point should be a Monday, got {oldest_date.strftime('%A')}"
)
def test_invalid_schedule():
r = restore_points("mirror", date(2026, 4, 15))
assert isinstance(r, dict) and "error" in r, f"should return an error, got {r}"
if __name__ == "__main__":
test_gfs_total()
test_gfs_weekly_sundays()
test_gfs_monthly_firsts()
test_gfs_month_end()
test_no_point_after_the_date()
test_time_machine_count()
test_time_machine_newest_weekly()
test_time_machine_oldest_point()
test_invalid_schedule()
print("All sample tests passed.") A hint
Start with the GFS branch: build three lists (daily, weekly, monthly) with plain timedelta arithmetic. Keep them in a dict keyed by the date and resolve clashes in favour of the earlier kind (daily beats weekly, weekly beats monthly). Then sort the dict's items newest-first before returning.
Results of the sample tests
| Test | Result | Details |
|---|
What your code printed
The sample tests run on this device, in your browser (Pyodide): nothing is sent to mysmartcopilot.com. The first run downloads Python (about 13.5 MB), which is kept for the next runs. A check in your browser is feedback for you, not proof that the code is right for every input.
Practice that adapts to you
Practise this lesson
13 questions about 6 ideas of this lesson. Each answer is explained at once, and what you get right is kept in this browser.
Interview questions
Warm-up (fresher to 2–5 years): a user asks whether their files are safe because the folder is in OneDrive. What do you say, in one minute?
OneDrive is a sync service, not a backup. The folder lives in Microsoft’s cloud and on every device the user signs in on, so a dead laptop does not lose the files. But a delete on one device syncs to all the others, and so do a wrong save and ransomware. The recycle bin helps only for a while: Microsoft gives a personal account 30 days and a work or school account 93, which an administrator can change. A loss noticed after that has nothing left to restore. A real backup adds a longer version history, an offline or immutable copy that ransomware cannot reach and a restore that has been tested. So I would tell the user that OneDrive protects against a lost laptop, not against a mistake, and set up a monthly offline copy as well.
Think about these two for a moment, then open each one to see the first step from the question bank:
Model answers open with any pass: ₹79 for 1 week ($2.99), one payment that never renews.
-
Fresher to mid
A small design firm asks you for a backup plan. They have a 2 TB file server, 20 Mbit/s uplink, 200 Mbit/s LAN. Give an RPO and an RTO you would propose, with the arithmetic, and the schedule that meets them.
-
Mid to senior
A charity's file server has been encrypted by ransomware overnight. Their backups are a nightly job to a USB disk that stays plugged in, plus a OneDrive sync of the users' documents. How do you recover and what do you change for next time?
Flashcards · 6 cards
Recall it, then check
Say the answer to yourself before you look: recalling it is what makes it stick.
-
How do full, incremental, differential and synthetic full backups trade off?
A full copies everything every run. An incremental run is small, but a restore reads the last full and every incremental after it. A differential grows each run but restores in two reads. A synthetic full gives a one-step restore without reading the source again, at the storage cost of a full.
-
What is the 3-2-1 rule, and what does current ransomware guidance add to it?
Three copies, on two kinds of media, with one offsite, as a planning minimum. Current guidance adds one copy that is offline or immutable.
-
Why keep a rotation of backups rather than only the newest one?
So that a corruption noticed late can still be rolled back. Grandfather-father-son keeps daily, weekly and monthly tiers, and Time Machine keeps hourly, daily and weekly points.
-
Where do the RPO and the RTO of a backup plan come from?
The RPO, the oldest change you accept to lose, comes from the schedule: a nightly backup gives one day. The RTO, how long you can stay down, comes from the restore. Both are agreed with the business.
-
A user says their files are safe because the folder is in OneDrive. What do you tell them?
OneDrive syncs; it is not a backup. A delete, a wrong save or ransomware on one device syncs to all the others, and its recycle bin helps only for a while, so a loss noticed late needs a real backup.
-
When does a backup count as real?
Only once a restore from it has been tried, has worked and has been recorded. Test often enough that each change to the plan is proven before anyone relies on it.
Key takeaways
- Four backup kinds trade storage, backup window and restore chain against each other; a synthetic full gives a one-step restore without reading the source again.
- 3-2-1 is a planning minimum - three copies, two media, one offsite - and current ransomware guidance adds one offline or immutable copy.
- Rotation keeps a history, not only the newest copy, so a corruption noticed late can still be rolled back; GFS gives daily, weekly and monthly tiers, and Time Machine keeps hourly, daily and weekly points under Apple’s documented rule.
- RPO comes from the schedule and RTO comes from the restore; both numbers are agreed with the business, with worked arithmetic from a real failure.
- File sync and RAID both mirror a delete to every copy, so neither is a backup; sync services keep a short recycle bin that only helps a loss noticed quickly.
- A backup is only real once a restore test from it works and is recorded; test often enough that every change to the plan is proven before it is relied on.
Terms in this lesson
- 3-2-1 rule
- A planning rule of thumb for backups: keep 3 copies of the data, on at least 2 different kinds of media, with 1 copy stored offsite or offline. Current ransomware guidance adds that one copy is offline or immutable.
- backup rotation
- A rule that chooses which backup copies to keep and which to overwrite as new ones arrive. A good rotation keeps a mix of recent, weekly and monthly copies so an older state is still reachable when a corruption is found late.
- deduplication
- Storing one physical copy of any run of bytes that would otherwise appear in several files or several backup runs. It cuts the storage a schedule needs, so a longer retention becomes affordable on the same disks.
- differential backup
- A backup that copies every file changed since the last full backup. Each differential run is larger than the one before, but a restore reads only two things: the last full plus the last differential.
- file versioning
- Keeping older copies of a file alongside its current one, so an edit, a wrong save or an encryption can be rolled back to any kept point. OneDrive, SharePoint and Windows File History all keep versions.
- full backup
- A backup that copies every file in scope on every run. It is the simplest kind to restore, because one copy holds everything, but it takes the most storage and the longest backup window.
- grandfather-father-son
- A rotation that keeps three tiers of copies: a daily one for the last 7 days, a weekly one for the last few Sundays and a monthly one for the first of the last 12 months. Clashing dates keep the shorter tier.
- immutable backup
- A backup stored so the data cannot be changed or deleted before a set date, usually through write-once-read-many media or an object store with object-lock turned on. It gives the same effect as offline media against a live attack.
- incremental backup
- A backup that copies only the files changed since the last backup of any kind. The run is small and quick, but a restore reads the last full copy and every incremental after it, in order.
- offline backup
- A backup copy kept on a device that is disconnected from the production network between runs, so that malware on a live machine cannot reach it. CISA's #StopRansomware Guide asks for offline, encrypted, tested backups.
- recovery point objective (RPO)
- The oldest change a backup plan accepts to lose when the system fails. A nightly backup gives an RPO of one day; a backup every 4 hours gives an RPO of 4 hours. A shorter RPO costs more storage and bandwidth.
- recovery time objective (RTO)
- The longest time a business accepts to stay down before data and services are back. It covers finding the backup, mounting it, restoring the data and testing that users can work again, not only the copy time.
- restore test
- A rehearsed restore from a backup copy to a scratch target, checked against the live data by file counts, hashes or a user's spot checks. Only a restore that was tested is proven to work; untested backups fail at the worst time.
- retention policy
- A written rule for how long each kind of backup copy is kept and when it is deleted. It balances the time a user has to notice a loss, the storage cost and the time to find a given file in the history.
- synthetic full backup
- A full copy that the backup server builds from the last full backup and every incremental since it, without reading the live source again. The restore side sees a full copy, so there is no incremental chain to replay.
References
- #StopRansomware Guide (Cybersecurity and Infrastructure Security Agency)
- Back up and restore your Mac with Time Machine (Apple)
- Restore deleted files or folders in OneDrive (Microsoft)
- Back up your Windows PC (Microsoft)
Related tools
Report a problem with this lesson
Kept only in this browser. Your Learn progress