{"id":28931478,"url":"https://github.com/rumenmitov/snapper","last_synced_at":"2025-08-25T17:06:06.763Z","repository":{"id":298066459,"uuid":"996755887","full_name":"rumenmitov/snapper","owner":"rumenmitov","description":"Snapper: Persistent System Snapshots","archived":false,"fork":false,"pushed_at":"2025-08-23T14:04:27.000Z","size":1160,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2025-08-23T14:56:41.418Z","etag":null,"topics":["backups","ext4","genode","goa","persistence","snapshot"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/rumenmitov.png","metadata":{"files":{"readme":"README.org","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":"docs/roadmap/ROADMAP.org","authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-06-05T12:18:14.000Z","updated_at":"2025-08-23T14:04:30.000Z","dependencies_parsed_at":"2025-06-09T08:34:30.272Z","dependency_job_id":"68a9200a-c6de-4148-b181-0cf39f59a83c","html_url":"https://github.com/rumenmitov/snapper","commit_stats":null,"previous_names":["rumenmitov/snapper"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/rumenmitov/snapper","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rumenmitov%2Fsnapper","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rumenmitov%2Fsnapper/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rumenmitov%2Fsnapper/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rumenmitov%2Fsnapper/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rumenmitov","download_url":"https://codeload.github.com/rumenmitov/snapper/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rumenmitov%2Fsnapper/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":272100683,"owners_count":24873442,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-25T02:00:12.092Z","response_time":1107,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["backups","ext4","genode","goa","persistence","snapshot"],"created_at":"2025-06-22T16:06:22.645Z","updated_at":"2025-08-25T17:06:06.752Z","avatar_url":"https://github.com/rumenmitov.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"#+title: Snapper 2.0\n#+author: Rumen Mitov\n#+email: rumen.mitov@constructor.tech\n\n[[./assets/snapper.png]]\n\nSnapper 2.0 (or just Snapper) is a snapshot mechanism for the virtual memory space of the persistent operating system PhantomOS. It uses the a logging file system (e.g. ext4) to ensure that file operations (e.g. modification or deletion) are resistant to OS crashes mid-way through the operation.\n\nA vital property of Snapper is that it needs to be disk space efficient in order not to bloat the file system. This is done by utilizing a mapping from the virtual pages (from now on referred only as pages) to a file containing their contents. Thus if a page remains unchanged its contents will still be mapped to a file from a previous snapshot, hence no new file needs to be created.\n\n* Requirements\n- Genode + Goa\n- [[https://codeberg.org/jws/genode-wundertuete/src/branch/25.05-2025-07-07][Lwext4 Plugin]] (optional)\n\n* Installation\nInstall the requirements. This pre-built container image comes with all the dependencies needed for Genode:\n#+begin_src shell\n  git clone --depth 1 https://github.com/genodelabs/genode.git\n  git clone --depth 1 https://github.com/genodelabs/goa.git genode/goa\n  git clone --depth 1 https://github.com/rumenmitov/snapper genode/repos/snapper\n\n  podman run -d --name genode --cap-add SYS_PTRACE -v $PWD/genode:/genode -w /genode docker.io/rmitov/genode:25.05 tail -f /dev/null\n#+end_src\n\n#+begin_quote\n❗ Make sure to setup Genode's build directory before continuing! ❗\n#+end_quote\n\nAdd the following to /\u003cgenode\u003e/build/x86_64/etc/build.conf/:\n\n: REPOSITORIES += $(GENODE_DIR)/repos/wundertuete # optional\n: REPOSITORIES += $(GENODE_DIR)/repos/snapper\n\nOptionally add the Lwext plugin:\n\n: git clone -b 25.05-2025-07-07 --depth 1 https://codeberg.org/jws/genode-wundertuete.git genode/repos/wundertuete\n\nRun this inside the container:\n\n#+begin_src shell\n  /genode/tool/ports/prepare_port lwext4\n  DEPOT_DIR=/genode/repos/snapper/var/depot goa depot-dir\n  DEPOT_DIR=/genode/repos/snapper/var/depot FORCE_VERSION=2025-07-09 /genode/tool/depot/create rumen/bin/x86_64/vfs_lwext4\n\n  mkdir /genode/repos/snapper/raw\n  dd if=/dev/zero of=/genode/repos/snapper/raw/snapper_block.raw bs=1M seek=16 count=0\n  mkfs.ext4 -O^metadata_csum -F /genode/repos/snapper/raw/snapper_block.raw\n#+end_src\n\n* Running Snapper\nIf you are using the container, the following should be run inside the container.\n\n** With Goa\n:properties:\n:custom_id: with-goa\n:end:\n\n#+begin_quote\n*NOTE* The runtime file _pkg/snapper/runtime_ is made to persist changes made to the block storage during the execution of the program. _pkg/snapper_ itself does not make any changes; the runtime file exists for potential future debugging purposes.\n\nFor a non-persistent runtime, see _pkg/snappertests/runtime_.\n#+end_quote\n\n#+begin_src shell\n  cd /genode/repos/snapper\n  goa run --pkg snapper\n#+end_src\n\nThis will run the main Snapper binary. If instead you want to run the tests:\n\n: goa run --pkg snappertests\n\nTo specify the number of snapshot objects that should be in the test simulation (~TESTS~ defaults to 1000):\n\n: TESTS=50 goa run --pkg snappertests\n\n** With Run Script\n\n#+begin_src shell\n  cd /genode\n  make -C build/x86_64 run/snapper KERNEL=linux BOARD=linux\n#+end_src\n\nOr, to run the tests:\n\n: make -C build/x86_64 run/snappertests KERNEL=linux BOARD=linux\n\nTo (optionally) specify how many test objects to create (see [[#with-goa][Running With Goa]] for more details):\n\n: TESTS=50 make -C build/x86_64 run/snappertests KERNEL=linux BOARD=linux\n\n#+begin_quote\nNOTE: On subsequent runs, if you want to change ~TESTS~, you have to ~rm -rf /genode/build/x86_64/test/snapper/~ before running.\n#+end_quote\n\n** Integration Into Another Project\nThe Snapper library is available for most run scripts and Goa projects. First run:\n\n: ./\u003cgenode-dir\u003e/depot/tool/extract rumen/src/snap\n\n- For run scripts just add =lib/snap= to the build artifacts.\n- For Goa, add =rumen/api/snap/2025-08-05= to the _archives_ file and run:\n\n\n* Configuration of Snapper\n:properties:\n:custom_id: configuration\n:end:\nSnapper should be configurable through Genode's XML. The configuration options are stored in ~Snapper::Config~:\n\n#+ATTR_LATEX: :environment longtable :align l|c|p{7cm}\n| \u003cl10\u003e         |    \u003cc30\u003e     |                                                     \u003cr50\u003e |\n| OPTION        |     TYPE     |                                               DESCRIPTION |\n|---------------+--------------+-----------------------------------------------------------|\n| verbose       |     ~bool~     |                          Whether to print verbose output. |\n|---------------+--------------+-----------------------------------------------------------|\n| threshold     | ~unsigned int~ |  The maximum number of files in a _snapshot_ sub-directory. |\n|---------------+--------------+-----------------------------------------------------------|\n| integrity     |     ~bool~     |     If true, crash the system on failed integrity checks, |\n|               |              |                                  otherwise log a warning. |\n|---------------+--------------+-----------------------------------------------------------|\n| redundancy    | ~unsigned int~ |     After reaching this reference count, a redundant file |\n|               |              |             copy will be created for subsequent snapshot. |\n|---------------+--------------+-----------------------------------------------------------|\n| max_snapshots | ~unsigned int~ |           The maximum number of complete snapshots inside |\n|               |              |                                           _\u003csnapper-root\u003e_. |\n|---------------+--------------+-----------------------------------------------------------|\n| min_snapshots | ~unsigned int~ | The minimum number of generations that need to be present |\n|               |              |                               for a purge to be possible. |\n|---------------+--------------+-----------------------------------------------------------|\n| expiration    | ~unsigned int~ |             How many seconds a generation should be kept. |\n|               |  (seconds)   |                                                           |\n|---------------+--------------+-----------------------------------------------------------|\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frumenmitov%2Fsnapper","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frumenmitov%2Fsnapper","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frumenmitov%2Fsnapper/lists"}