{"id":19015474,"url":"https://github.com/hansolo/crac4","last_synced_at":"2025-04-23T01:49:50.468Z","repository":{"id":57832756,"uuid":"475979532","full_name":"HanSolo/crac4","owner":"HanSolo","description":"Another demo for the CRaC project","archived":false,"fork":false,"pushed_at":"2022-10-04T13:40:21.000Z","size":243,"stargazers_count":20,"open_issues_count":0,"forks_count":4,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-04-23T01:49:45.040Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/HanSolo.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2022-03-30T17:16:04.000Z","updated_at":"2024-08-16T10:43:26.000Z","dependencies_parsed_at":"2023-01-19T05:15:58.102Z","dependency_job_id":null,"html_url":"https://github.com/HanSolo/crac4","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/HanSolo%2Fcrac4","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/HanSolo%2Fcrac4/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/HanSolo%2Fcrac4/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/HanSolo%2Fcrac4/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/HanSolo","download_url":"https://codeload.github.com/HanSolo/crac4/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250354294,"owners_count":21416751,"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","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":[],"created_at":"2024-11-08T19:37:33.456Z","updated_at":"2025-04-23T01:49:50.451Z","avatar_url":"https://github.com/HanSolo.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"## CRaC 4 Demo\n\n### Short description\nThe demo uses a scheduled task to execute the method ```checkForPrimes()``` every 5 seconds.\nIn this method a loop will check 100_000 times a random number between 1 - 100_000 for prime.\nThe ```isPrime(long number)``` method will check if the given number exists in a cache and either\nreturn the result from the cache or calculate the result, put it in the cache and return it.\nThe cache that is used here, keeps it's items only for a time defined by timeout before they will be\nremoved from the cache automatically. Everytime a key is requested, it's lifetime in the cache will be\nextended by the given timeout value. This leads to the fact that keys that will be requested more often will stay\nin the cache where keys that are outdated will be removed from the cache.\nThe cache also uses a scheduled task that calls the ```clean()``` method once a second and starts after a \ngiven delay.\nThe cache timeout and the initial delay can be adjusted using properties file named ```crac4.properties``` which\nwill be stored in your user home folder.\nIt contains two entries:\n```\ninitial_cache_clean_delay=50\ncache_timeout=10\n```\nYou might need to adjust those values depending on your machine settings (e.g. on my M1 Mac the first run just took 2.5s where on my older Intel Mac it took 22s).\nYou just have to make sure that the cacheTimeout is not shorter than the time it takes to check the 100_000 numbers for prime, otherwise the cache will be cleaned\ntoo often and you don't see an decrease in calculation time.\n\n### We have two methods that will be called:\n\nThe \u003cb\u003echeckForPrimes()\u003c/b\u003e method will 100_000 times check a random number between 1 - 100_000 for prime.\nAfter checking all numbers it will print out the time it took to check all numbers on the console and\nincrease a counter.\n```java\nprivate void checkForPrimes() {\n    long start = System.nanoTime();\n    for (long i = 1 ; i \u003c= 100_000 ; i++) {\n        isPrime(RND.nextInt(100_000));\n    }\n    System.out.println(counter + \". Run: \" + ((System.nanoTime() - start) / 1_000_000 + \" ms (\" + primeCache.size() + \" elements cached, \" + String.format(Locale.US, \"%.1f%%\", primeCache.size() / 1_000.0) + \")\"));\n    counter++;\n}\n```\n\nThe \u003cb\u003eisPrime(final long number)\u003c/b\u003e method will be called for each number and either directly returns\nthe result (in case it's already in the cache) or calculates the result and stores it in the cache.\n```java\nprivate boolean isPrime(final long number) {\n    if (number \u003c 1) { return false; }\n    if (primeCache.containsKey(number)) { return primeCache.get(number).get(); }\n    boolean isPrime = true;\n    for (long n = number ; n \u003e 0 ; n--) {\n        if (n != number \u0026\u0026 n != 1 \u0026\u0026 number % n == 0) {\n            isPrime = false;\n            break;\n        }\n    }\n    primeCache.put(number, isPrime);\n    return isPrime;\n}\n```\n\n### Install and run the code:\nYou need a Linux x64 machine to run the pre-build OpenJDK version incl. CRaC (e.g. Ubuntu on an Intel machine).\n\n\u003cbr\u003e\n\n#### Download [OpenJDK pre-build incl. CRaC](https://github.com/CRaC/openjdk-builds/releases/):\n```wget https://github.com/CRaC/openjdk-builds/releases/download/17-crac%2B3/openjdk-17-crac+3_linux-x64.tar.gz```\n\n\u003cbr\u003e\n\n#### Extract the tar.gz file with sudo rights:\nMake sure you have a folder\n```\n/usr/lib/jvm\n```\notherwise create it by using\n```\nsudo mkdir /usr/lib/jvm\n```\nNow extract the tar.gz file\n```shell\nsudo tar zxvf openjdk-17-crac+3_linux-x64.tar.gz -C /usr/lib/jvm\n```\n\n\u003cbr\u003e\n\n#### Set JAVA_HOME and add it to PATH:\n```\n$ export JAVA_HOME=/usr/lib/jvm/openjdk-17-crac+3_linux-x64\n$ export PATH=$JAVA_HOME/bin:$PATH\n$ java -version\nopenjdk version \"17-crac\" 2021-09-14\nOpenJDK Runtime Environment (build 17-crac+3-15)\nOpenJDK 64-Bit Server VM (build 17-crac+3-15, mixed mode, sharing)\n```\n\n\u003cbr\u003e\n\n#### Clone this repository:\nMake sure you have git installed on your machine, otherwise install it by using\n```\n$ sudo apt update\n$ sudo apt install git\n```\nNow clone this repository\n```\n$ git clone https://github.com/HanSolo/crac4\n```\n\n\u003cbr\u003e\n\n#### Build the jar\n```\n$ cd crac\n$ ./gradlew clean build\n```\n\n\u003cbr\u003e\n\n#### Run the example\nMake sure you have the folder ```crac-files``` in your home folder, otherwise create it with\n```\n$ cd ~\n$ mkdir crac-files\n```\n\nOpen a shell (SHELL 1)\n```\ncd /build/libs\njava -XX:CRaCCheckpointTo=/home/YOUR_USER_NAME/crac-files -jar ./crac4-17.0.0.jar\n```\nNow you should see something as follows on your screen:\n```\nRunning on CRaC (PID 20719)\n1. Run 27935 ms (63254 elements in cache)\n2. Run 10290 ms (86556 elements in cache)\n3. Run 3828 ms (95142 elements in cache)\n4. Run 1378 ms (98244 elements in cache)\n5. Run 527 ms (99336 elements in cache)\n6. Run 214 ms (99775 elements in cache)\n7. Run 77 ms (99918 elements in cache)\n8. Run 43 ms (99973 elements in cache)\n9. Run 26 ms (99992 elements in cache)\n10. Run 14 ms (99995 elements in cache)\n11. Run 20 ms (99997 elements in cache)\n12. Run 14 ms (99999 elements in cache)\n13. Run 18 ms (100000 elements in cache)\n```\n\nOpen another shell (SHELL 2) and execute the following command to create the checkpoint\n```\n$ cd /CRAC_PROJECT_FOLDER/build/libs\n$ jcmd crac4-17.0.0.jar JDK.checkpoint\n20719:\nCommand executed successfully\n```\n\nSHELL 1 should now show something as follows:\n```\nRunning on CRaC (PID 20719)\n1. Run 27935 ms (63254 elements in cache)\n2. Run 10290 ms (86556 elements in cache)\n3. Run 3828 ms (95142 elements in cache)\n4. Run 1378 ms (98244 elements in cache)\n5. Run 527 ms (99336 elements in cache)\n6. Run 214 ms (99775 elements in cache)\n7. Run 77 ms (99918 elements in cache)\n8. Run 43 ms (99973 elements in cache)\n9. Run 26 ms (99992 elements in cache)\n10. Run 14 ms (99995 elements in cache)\n11. Run 20 ms (99997 elements in cache)\n12. Run 14 ms (99999 elements in cache)\n13. Run 18 ms (100000 elements in cache)\nbeforeCheckpoint() called in Main\nbeforeCheckpoint() called in GenericCache\nCR: Checkpoint ...\nKilled\n```\n\nIn the first shell (SHELL 1) window where you started the jar file, restore the checkpoint by calling\n```\nRunning on CRaC (PID 20719)\n1. Run 27935 ms (63254 elements in cache)\n2. Run 10290 ms (86556 elements in cache)\n3. Run 3828 ms (95142 elements in cache)\n4. Run 1378 ms (98244 elements in cache)\n5. Run 527 ms (99336 elements in cache)\n6. Run 214 ms (99775 elements in cache)\n7. Run 77 ms (99918 elements in cache)\n8. Run 43 ms (99973 elements in cache)\n9. Run 26 ms (99992 elements in cache)\n10. Run 14 ms (99995 elements in cache)\n11. Run 20 ms (99997 elements in cache)\n12. Run 14 ms (99999 elements in cache)\n13. Run 18 ms (100000 elements in cache)\nbeforeCheckpoint() called in Main\nbeforeCheckpoint() called in GenericCache\nCR: Checkpoint ...\nKilled\n$ java -XX:CRaCRestoreFrom=/home/YOUR_USER_NAME/crac-files\n```\n\nIf everything worked as expected you should now see the program continue to run\n```\nRunning on CRaC (PID 20719)\n1. Run 27935 ms (63254 elements in cache)\n2. Run 10290 ms (86556 elements in cache)\n3. Run 3828 ms (95142 elements in cache)\n4. Run 1378 ms (98244 elements in cache)\n5. Run 527 ms (99336 elements in cache)\n6. Run 214 ms (99775 elements in cache)\n7. Run 77 ms (99918 elements in cache)\n8. Run 43 ms (99973 elements in cache)\n9. Run 26 ms (99992 elements in cache)\n10. Run 14 ms (99995 elements in cache)\n11. Run 20 ms (99997 elements in cache)\n12. Run 14 ms (99999 elements in cache)\n13. Run 18 ms (100000 elements in cache)\nbeforeCheckpoint() called in Main\nbeforeCheckpoint() called in GenericCache\nCR: Checkpoint ...\nKilled\n$ java -XX:CRaCRestoreFrom=/home/YOUR_USER_NAME/crac-files\nafterRestore() called in GenericCache\nafterRestore() called in Main\n14. Run 19 ms (100000 elements in cache)\n15. Run 16 ms (100000 elements in cache)\n16. Run 19 ms (100000 elements in cache)\n17. Run 15 ms (100000 elements in cache)\n18. Run 16 ms (100000 elements in cache)\nApp stopped in shutdown hook\n```\nNow you can stop the running app by pressing CTRL+C\n\nAs you can see the counter continued counting with 14 and did not restart from 1.\nAnd because the cache was also stored when we created the checkpoint, it will directly\nbe filled after we restore the app from the checkpoint. And with the cache filled, the\ncall to ```checkForPrimes()``` will return quickly.\nYou can imagine that this approach drastically reduces the startup times of applications.\n\n\u003c/br\u003e\n\n### Running the demo in a docker container (on a Linux x64 machine)\n#### 1. Create docker image\n1. Open a shell window\n2. Change to the crac4 folder\n3. Run ``` docker build -t crac4 . ``` to build the docker image\n\n\u003c/br\u003e\n\n#### 2. Start the application in a docker container\n1. Open a shell window\n2. Run ``` docker run -it --privileged --rm --name crac4 crac4 ```\n3. In the docker container run\u003c/br\u003e \n   ``` \n   cd /opt/app \n   java -XX:CRaCCheckpointTo=/opt/crac-files -jar crac4-17.0.0.jar\n   ```\n4. Note the PID of the program   \n\n\u003c/br\u003e\n\n#### 3. Start a 2nd shell window and create the checkpoint\n1. Open a second shell window\n2. Run ``` docker exec -it -u root crac4 /bin/bash ```\n3. Wait until the program in the first window reaches for example the 17th iteration\n4. Take the PID from shell 1 and run ``` jcmd PID JDK.checkpoint```\n5. In the first shell window the application should have created the checkpoint \n6. In second shell window run ``` exit ``` to get back to your machine\n\n\u003c/br\u003e\n\n#### 4. Commit the current state of the docker container \n1. Now get the CONTAINER_ID from shell window 1 by execute ``` docker ps -a ``` in shell window 2\n2. Run ``` docker commit CONTAINER_ID crac4:checkpoint ``` in shell window 2\n3. Go back to shell window 1 and execute ```exit``` to stop the container\n\n\u003c/br\u003e\n\n#### 5. Run the docker container from the saved state incl. the checkpoint\nNow you can start the docker container from the checkpoint by executing\n``` docker run -it --privileged --rm --name crac4 crac4:checkpoint java -XX:CRaCRestoreFrom=/opt/crac-files ```\n\n\u003c/br\u003e\n\n#### 6. Create a shell script to restore multiple times\n1. Open a shell window\n2. Create a text file named ```restore_docker.sh```\n3. Add\n```\n#!/bin/bash\n\necho \"docker run -it --privileged --rm --name $1 crac4:checkpoint java -XX:CRaCRestoreFrom=/opt/crac-files\"\n\ndocker run -it --privileged --rm --name $1 crac4:checkpoint java -XX:CRaCRestoreFrom=/opt/crac-files\n```\n4. Make the script executable by executing ```chmod +x restore_docker.sh```\n5. Now you can start the docker container multiple times executing ```restore_docker.sh NAME_OF_CONTAINER```\n\nIf you would like to start the original container without the checkpoint you can still\ndo that by executing the following command\n```\ndocker run -it --privileged --rm --name crac4 crac4 java -jar /opt/app/crac4-17.0.0.jar\n```","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhansolo%2Fcrac4","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhansolo%2Fcrac4","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhansolo%2Fcrac4/lists"}