{"id":20495196,"url":"https://github.com/samuelebortolotti/multilevel-cache","last_synced_at":"2026-05-06T17:34:40.990Z","repository":{"id":77067949,"uuid":"496205945","full_name":"samuelebortolotti/multilevel-cache","owner":"samuelebortolotti","description":"Repository concerning a multi-level distributed cache implementation developed for the Distributed Systems 1 course of the master's degree in Computer Science at University of Trento ","archived":false,"fork":false,"pushed_at":"2022-08-08T13:28:01.000Z","size":1097,"stargazers_count":1,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-08-21T18:44:05.349Z","etag":null,"topics":["akka","distributed-systems","docker","gradle","java-8","multilevel-cache"],"latest_commit_sha":null,"homepage":"","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/samuelebortolotti.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,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-05-25T11:42:05.000Z","updated_at":"2025-02-22T12:16:24.000Z","dependencies_parsed_at":null,"dependency_job_id":"3120f812-f035-4db5-b26e-0cc4c062c6dd","html_url":"https://github.com/samuelebortolotti/multilevel-cache","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/samuelebortolotti/multilevel-cache","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/samuelebortolotti%2Fmultilevel-cache","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/samuelebortolotti%2Fmultilevel-cache/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/samuelebortolotti%2Fmultilevel-cache/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/samuelebortolotti%2Fmultilevel-cache/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/samuelebortolotti","download_url":"https://codeload.github.com/samuelebortolotti/multilevel-cache/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/samuelebortolotti%2Fmultilevel-cache/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32704546,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-06T08:33:17.875Z","status":"ssl_error","status_checked_at":"2026-05-06T08:33:17.221Z","response_time":117,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":["akka","distributed-systems","docker","gradle","java-8","multilevel-cache"],"created_at":"2024-11-15T17:44:55.278Z","updated_at":"2026-05-06T17:34:40.976Z","avatar_url":"https://github.com/samuelebortolotti.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Distributed System 1 Project\n\nThis repository concerns all about the Distributed System 1 project employing [Java 8](https://www.oracle.com/java/technologies/java8.html) and [Akka](https://akka.io/).\n\nThe project entails putting a **distributed multi-level cache** protocol into practice.\nDue to the fact that caches store frequently requested objects and respond to the majority of client requests independently, their main purpose is to avoid database congestion.\nThe Akka actors involved are clients, caches, and a single database.\n\nMultiple clients that can read and write data stored in a database make up the system.\nThe system has been designed with read operations in mind, which are instantly handled by the cache layer located near to the clients.\nAs an alternative, write operations always use the primary database. Clients interacting with the same cache are assured _not_ to receive outdated values once their write operations have been validated, \nand the protocol should offer **eventual consistency**.\nAdditionally, two \"critical\" variations of the fundamental operations, namely _CRITREAD_ and _CRITWRITE_, which offer better assurances.\n\nBy assumption, the database store remains constant during the protocol's execution.\n\u003e For the sake of simplicity the data stored in databases and caches is made up of integer numbers.\n\nMoreover, according to the project statement, caches come with an initial **tree structure** which needs to be specified.\n\nSome caches operate at the first level, with a direct connection to the database. We refer to those as **L1** caches. \nL1 caches are the parents of **L2** caches in the tree. The latter interact with clients, receiving their requests and responding with the results.\n\nThe provided operations are:\n\n- **READ**: If the requested value is present in memory when an L2 cache gets a Read, it responds right away with it.\nIf not, it will get in touch with the parent L1 cache.\nThe main database may be contacted or the L1 cache may respond with the value (typically referred to as read-through mode).\nUntil the customer is contacted, responses travel backward along the path of the request.\nCaches store the item on the way back for upcoming requests.\nClient timeouts ought to account for how long it takes a request to get to the database.\n- **WRITE**: The request is sent to the database, which executes the write operation and notifies all of its L1 caches of the update.\nIt is then sent to all associated L2 caches by all L1 caches.\nThis might theoretically apply the change to every cache, which is required for eventual consistency.\nThe written item will only be updated in caches that previously had it stored, so take note of this.\n- **CRITREAD**: Fetches the most recent value from the database, however unlike a read, the request is transmitted even if the item is already in the L2 or L1 cache.\n- **CRITWRITE**: The same as in Write, the request is sent to the database.\nHowever, the database must make sure that no cache contains an outdated value for the written item before the write operation is applied.\nNo client should be able to read the new value from any cache, followed by the old value.\nThe database propagates the change as for Write once it has confirmed that the cached objects have been deleted.\n\nA note on crashes and recoveries:\n\nCaches may crash working at critical algorithmic points.\nThe system need to use a straightforward timeout-based crash detection mechanism, as demonstrated in the labs.\nWhen a client notices that one L2 cache has crashed, it will choose another L2 cache and reroute its requests.\nThe primary database will be chosen as the parent by an L2 cache that notices that its L1 parent has crashed.\nCaches lose all stored objects when they crash (we presume they were saved in volatile memory).\nThey do, however, still preserve information about the system, such as the database actor and the ActorRef of their tree neighbors.\nAfter a set amount of time, caches recover and restart functioning.\n\n## Members\n\n|  Name    |  Surname   |     Username        |\n| :------: | :--------: | :-----------------: |\n| Samuele  | Bortolotti | `samuelebortolotti `|\n| Luca     | De Menego  | `lucademenego99`    |\n\n## Set Up\n\nYou can either use [Gradle](https://gradle.org/) to compile the code or you can run it in a [Docker](https://www.docker.com/) container.\n\n### Gradle\n\n\u003e To view every Gradle task available for this project, execute the command `gradle tasks`.\n\nGradle is used to both track the project's dependencies and compile it.\n\n#### Build\n\nTo compile the project you can run:\n\n```bash\ngradle clean build -x test\n```\n\n\u003e The -x test flag is used in order to avoid the test execution at compile time.\n\u003e Usually, the test execution is a good idea, however the requested time for the test to complete is around 10 minutes, \n\u003e which may be annoying.\n\n#### Run\n\nTo run the project you can use either the gradle command:\n\n```bash\ngradle run --args=\"--l1 5 --l2 3 --clients 1 --seconds 25\"\n```\n\nor you can run directly the produced jar file:\n\n```bash\njava -jar build/libs/DS1-project-1.0-VERSION.jar --l1 5 --l2 3 --clients 1 --seconds 25\n```\n\n\u003e Defaults are:\n\u003e ```java\n\u003e int countL1 = 5;\n\u003e int countL2 = 5;\n\u003e int countClients = 3;\n\u003e int secondsForIteration = 20;\n\u003e ```\n\nwhere the command line arguments are:\n\n- **clients** \u003cNumber of clients\u003e: Number of clients connected to the hierarchical distributed cache [default 5]\n- **l1** \u003cNumber of l1 caches\u003e: Number of L1 caches which will be present in the hierarchical distributed cache\n- **l2** \u003cNumber of l2 caches\u003e: Number of L2 caches which will be present in the hierarchical distributed cache\n- **seconds** \u003cNumber of seconds per iteration\u003e: Number of seconds each iteration takes\n\n\u003e For more information run either:\n\u003e \n\u003e `gradle run --args=\"--help\"`\n\u003e \n\u003e or:\n\u003e \n\u003e `java -jar build/libs/DS1-project-1.0-VERSION.jar --help`\n\n#### Documentation\n\nAlong with the report, you can generate the documentation of the project running the following gradle task:\n\n```bash\ngradle javadoc\n```\n\nThe documentation will be provided in the `build/docs/javadoc` folder.\nYou can open it using your favourite browser just by typing:\n\n```bash\nxdg-open build/docs/javadoc/index.html\n```\n\n#### Tests\n\nThe code comes along with some [JUnit](https://junit.org/junit5/docs/current/user-guide/) tests, you can run them with the following line:\n\n```bash\n$ gradle test\n```\n\nOr alternatively, they are run together with the build command, therefore either after a `gradle build` or a `gradle test` you can find the tests result in the `build/reports/tests/test/` folder.\n\nAgain, you can consult them opening the `index.html` file with your browser.\n\n```bash\nxdg-open build/reports/tests/test/index.html \n```\n\n### Docker\n\nThe image generated with the Dockerfile uses a multi-stage build in order to limit as much as possible the image size, by first compiling the code with a Gradle image and then run it using a `jre` one.\n\n#### Docker build\n\nTo build the image you can run:\n\n```bash\ndocker build -t ds1:latest .\n```\n\n#### Docker run\n\nTo run the application you can execute:\n\n```bash\ndocker run -it -e L1=5 -e L2=3 -e CLIENTS=1 -e SECONDS=25 ds1:latest\n```\n\nwhere the behaviour of the environment variables is the same as for the classic execution of the program.\n\n\u003e **Note**: the program **needs** a standard input to work properly; the -it flag is employed \n\u003e in order to instruct Docker to allocate a pseudo-TTY connected to the container’s stdin.\n\u003e \n\u003e If this option is not specified the Java [Scanner](https://docs.oracle.com/javase/7/docs/api/java/util/Scanner.html) will be stuck in an infinite loop\n\u003e expecting a keyboard input which will never come.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsamuelebortolotti%2Fmultilevel-cache","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsamuelebortolotti%2Fmultilevel-cache","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsamuelebortolotti%2Fmultilevel-cache/lists"}