Browse Source

OfficeFloor supporting Cache Test (#6670)

* Removing Rapidoid as seems dead project (no commit last year)

* Downloading from SourceForge

* Bump maven-compiler-plugin in /frameworks/Java/officefloor/src

Bumps [maven-compiler-plugin](https://github.com/apache/maven-compiler-plugin) from 3.8.0 to 3.8.1.
- [Release notes](https://github.com/apache/maven-compiler-plugin/releases)
- [Commits](https://github.com/apache/maven-compiler-plugin/compare/maven-compiler-plugin-3.8.0...maven-compiler-plugin-3.8.1)

Signed-off-by: dependabot-preview[bot] <[email protected]>

* Bump maven-shade-plugin in /frameworks/Java/officefloor/src

Bumps [maven-shade-plugin](https://github.com/apache/maven-shade-plugin) from 3.2.1 to 3.2.2.
- [Release notes](https://github.com/apache/maven-shade-plugin/releases)
- [Commits](https://github.com/apache/maven-shade-plugin/compare/maven-shade-plugin-3.2.1...maven-shade-plugin-3.2.2)

Signed-off-by: dependabot-preview[bot] <[email protected]>

* Fixing Raw OfficeFloor

* Specifying Spring plugin version

* Bump to OfficeFloor 3.21.0

* Bump spring-boot-maven-plugin in /frameworks/Java/officefloor/src

Bumps [spring-boot-maven-plugin](https://github.com/spring-projects/spring-boot) from 2.2.4.RELEASE to 2.2.5.RELEASE.
- [Release notes](https://github.com/spring-projects/spring-boot/releases)
- [Commits](https://github.com/spring-projects/spring-boot/compare/v2.2.4.RELEASE...v2.2.5.RELEASE)

Signed-off-by: dependabot-preview[bot] <[email protected]>

* Bump spring-boot-maven-plugin in /frameworks/Java/officefloor/src

Bumps [spring-boot-maven-plugin](https://github.com/spring-projects/spring-boot) from 2.2.5.RELEASE to 2.2.6.RELEASE.
- [Release notes](https://github.com/spring-projects/spring-boot/releases)
- [Commits](https://github.com/spring-projects/spring-boot/compare/v2.2.5.RELEASE...v2.2.6.RELEASE)

Signed-off-by: dependabot-preview[bot] <[email protected]>

* Bump net.officefloor:bom in /frameworks/Java/officefloor/src

Bumps [net.officefloor:bom](https://github.com/officefloor/OfficeFloor) from 3.21.0 to 3.22.0.
- [Release notes](https://github.com/officefloor/OfficeFloor/releases)
- [Commits](https://github.com/officefloor/OfficeFloor/commits)

Signed-off-by: dependabot-preview[bot] <[email protected]>

* Bump maven-shade-plugin in /frameworks/Java/officefloor/src

Bumps [maven-shade-plugin](https://github.com/apache/maven-shade-plugin) from 3.2.2 to 3.2.3.
- [Release notes](https://github.com/apache/maven-shade-plugin/releases)
- [Commits](https://github.com/apache/maven-shade-plugin/compare/maven-shade-plugin-3.2.2...maven-shade-plugin-3.2.3)

Signed-off-by: dependabot-preview[bot] <[email protected]>

* Bump net.officefloor:bom in /frameworks/Java/officefloor/src

Bumps [net.officefloor:bom](https://github.com/officefloor/OfficeFloor) from 3.22.0 to 3.23.0.
- [Release notes](https://github.com/officefloor/OfficeFloor/releases)
- [Commits](https://github.com/officefloor/OfficeFloor/commits)

Signed-off-by: dependabot-preview[bot] <[email protected]>

* Bump net.officefloor:bom in /frameworks/Java/officefloor/src

Bumps [net.officefloor:bom](https://github.com/officefloor/OfficeFloor) from 3.23.0 to 3.24.0.
- [Release notes](https://github.com/officefloor/OfficeFloor/releases)
- [Commits](https://github.com/officefloor/OfficeFloor/commits)

Signed-off-by: dependabot-preview[bot] <[email protected]>

* Bump spring-boot-maven-plugin in /frameworks/Java/officefloor/src

Bumps [spring-boot-maven-plugin](https://github.com/spring-projects/spring-boot) from 2.2.6.RELEASE to 2.2.7.RELEASE.
- [Release notes](https://github.com/spring-projects/spring-boot/releases)
- [Commits](https://github.com/spring-projects/spring-boot/compare/v2.2.6.RELEASE...v2.2.7.RELEASE)

Signed-off-by: dependabot-preview[bot] <[email protected]>

* Bump spring-boot-maven-plugin in /frameworks/Java/officefloor/src

Bumps [spring-boot-maven-plugin](https://github.com/spring-projects/spring-boot) from 2.2.7.RELEASE to 2.3.0.RELEASE.
- [Release notes](https://github.com/spring-projects/spring-boot/releases)
- [Commits](https://github.com/spring-projects/spring-boot/compare/v2.2.7.RELEASE...v2.3.0.RELEASE)

Signed-off-by: dependabot-preview[bot] <[email protected]>

* Bump net.officefloor:bom in /frameworks/Java/officefloor/src

Bumps [net.officefloor:bom](https://github.com/officefloor/OfficeFloor) from 3.24.0 to 3.25.0.
- [Release notes](https://github.com/officefloor/OfficeFloor/releases)
- [Commits](https://github.com/officefloor/OfficeFloor/commits)

Signed-off-by: dependabot-preview[bot] <[email protected]>

* Bump maven-shade-plugin in /frameworks/Java/officefloor/src

Bumps [maven-shade-plugin](https://github.com/apache/maven-shade-plugin) from 3.2.3 to 3.2.4.
- [Release notes](https://github.com/apache/maven-shade-plugin/releases)
- [Commits](https://github.com/apache/maven-shade-plugin/compare/maven-shade-plugin-3.2.3...maven-shade-plugin-3.2.4)

Signed-off-by: dependabot-preview[bot] <[email protected]>

* Bump spring-boot-maven-plugin in /frameworks/Java/officefloor/src

Bumps [spring-boot-maven-plugin](https://github.com/spring-projects/spring-boot) from 2.3.0.RELEASE to 2.3.1.RELEASE.
- [Release notes](https://github.com/spring-projects/spring-boot/releases)
- [Commits](https://github.com/spring-projects/spring-boot/compare/v2.3.0.RELEASE...v2.3.1.RELEASE)

Signed-off-by: dependabot-preview[bot] <[email protected]>

* Bump spring-boot-maven-plugin in /frameworks/Java/officefloor/src

Bumps [spring-boot-maven-plugin](https://github.com/spring-projects/spring-boot) from 2.3.1.RELEASE to 2.3.2.RELEASE.
- [Release notes](https://github.com/spring-projects/spring-boot/releases)
- [Commits](https://github.com/spring-projects/spring-boot/compare/v2.3.1.RELEASE...v2.3.2.RELEASE)

Signed-off-by: dependabot-preview[bot] <[email protected]>

* Bump net.officefloor:bom in /frameworks/Java/officefloor/src

Bumps [net.officefloor:bom](https://github.com/officefloor/OfficeFloor) from 3.25.0 to 3.26.0.
- [Release notes](https://github.com/officefloor/OfficeFloor/releases)
- [Commits](https://github.com/officefloor/OfficeFloor/compare/release-3.25.0...release-3.26.0)

Signed-off-by: dependabot-preview[bot] <[email protected]>

* Bump spring-boot-maven-plugin in /frameworks/Java/officefloor/src

Bumps [spring-boot-maven-plugin](https://github.com/spring-projects/spring-boot) from 2.3.2.RELEASE to 2.3.3.RELEASE.
- [Release notes](https://github.com/spring-projects/spring-boot/releases)
- [Commits](https://github.com/spring-projects/spring-boot/compare/v2.3.2.RELEASE...v2.3.3.RELEASE)

Signed-off-by: dependabot-preview[bot] <[email protected]>

* Bump net.officefloor:bom in /frameworks/Java/officefloor/src

Bumps [net.officefloor:bom](https://github.com/officefloor/OfficeFloor) from 3.26.0 to 3.27.0.
- [Release notes](https://github.com/officefloor/OfficeFloor/releases)
- [Commits](https://github.com/officefloor/OfficeFloor/commits)

Signed-off-by: dependabot-preview[bot] <[email protected]>

* Bump spring-boot-maven-plugin in /frameworks/Java/officefloor/src

Bumps [spring-boot-maven-plugin](https://github.com/spring-projects/spring-boot) from 2.3.3.RELEASE to 2.3.4.RELEASE.
- [Release notes](https://github.com/spring-projects/spring-boot/releases)
- [Commits](https://github.com/spring-projects/spring-boot/compare/v2.3.3.RELEASE...v2.3.4.RELEASE)

Signed-off-by: dependabot-preview[bot] <[email protected]>

* Bump net.officefloor:bom in /frameworks/Java/officefloor/src

Bumps [net.officefloor:bom](https://github.com/officefloor/OfficeFloor) from 3.27.0 to 3.28.0.
- [Release notes](https://github.com/officefloor/OfficeFloor/releases)
- [Commits](https://github.com/officefloor/OfficeFloor/commits)

Signed-off-by: dependabot-preview[bot] <[email protected]>

* Fixing to run with v3.28.0

* Including Undertow

* Using slim docker images

* Fixing to add all supported tests

* Increasing connection pool size

* Write up the 503 errors and why

* Fix grammer

* Bump spring-boot-maven-plugin in /frameworks/Java/officefloor/src

Bumps [spring-boot-maven-plugin](https://github.com/spring-projects/spring-boot) from 2.3.4.RELEASE to 2.3.5.RELEASE.
- [Release notes](https://github.com/spring-projects/spring-boot/releases)
- [Commits](https://github.com/spring-projects/spring-boot/compare/v2.3.4.RELEASE...v2.3.5.RELEASE)

Signed-off-by: dependabot-preview[bot] <[email protected]>

* Improving chances of full processing

Increasing max thread counts to have thread per client.  Also, shading
jars correctly.

Plus adding in DB test for raw

* Fixing raw test to have database

* Ensure random numbers to avoid cached entities

* Ensuring spring random numbers to avoid entity caching

* Adding queries for raw

* officefloor-raw queries passing

* office-raw supporting all requests

* Fixed update test to ensure updates occur before responding

* Adding officefloor-async

This will demonstrate OfficeFloor running as a single thread
asynchronous server

* Upgrading to OfficeFloor 2.38.1

* Tidy up read me

* Appropriate back pressure queue

* Handle rate limiting

* Providing appropriate throttling

* Lowering threading to handle through put

* officefloor-raw passing tests

* Passing tests

* OfficeFloor 3.28.2

* Fixing rate limiting

* Bump net.officefloor:bom in /frameworks/Java/officefloor/src

Bumps [net.officefloor:bom](https://github.com/officefloor/OfficeFloor) from 3.28.2 to 3.29.0.
- [Release notes](https://github.com/officefloor/OfficeFloor/releases)
- [Commits](https://github.com/officefloor/OfficeFloor/commits)

Signed-off-by: dependabot-preview[bot] <[email protected]>

* Fixing for bump to 3.30.0

* Increasing max direct memory

* Increasing threshold to enable verifications to pass for officefloor-raw

* Start script to take available memory into consideration

* Max direct memory aware of available memory

Also, cleaning writer threads of buffers to avoid leaks.

* Avoiding OOM by managing disable/enable reading

* DB and Fortune passing

* Ensuring free command is available

* Removing TODOs

* Increasing reactor buffer for multiple queries

* Fixing for 3.30.1

* Passing benchmark tests

* Avoiding OOM on reactor buffer sizes

* Passing validate tests

* Using defaults from 3.30.1

* Bump to 512 threads and connections

* Reverting dockerfiles to provide appropriate parameters

* openjdk:slim for apt-get available

* Providing thread affinity to raw

* Fixing rate limit throttling

* Multiplexing queries over connections per socket

* Fixing for large queries in validate

* Fixing versions of maven and java

* Providing thread affinity of DB connection thread

* Fixing for Netty event loop thread

* Tidying up compiler warnings

* Single db pool to avoid additional threads

* Use default LoopResources

* Tidying up code for warnings

* Further tidy up of code

* Revert to latest pull request

* Using parallel GC for better throughput

* Fix up for thread local buffering improvements

* OfficeFloor fortune raw

Focus of officefloor-raw is raw performance of the OfficeFloor HTTP
server.  Using raw fortune to remove mustache overheads.

* Tidy up loop

* Server name (as per discussions)

* Bump spring-boot-maven-plugin in /frameworks/Java/officefloor/src

Bumps [spring-boot-maven-plugin](https://github.com/spring-projects/spring-boot) from 2.3.5.RELEASE to 2.4.2.
- [Release notes](https://github.com/spring-projects/spring-boot/releases)
- [Commits](https://github.com/spring-projects/spring-boot/compare/v2.3.5.RELEASE...v2.4.2)

Signed-off-by: dependabot-preview[bot] <[email protected]>

* Bump net.officefloor:bom in /frameworks/Java/officefloor/src

Bumps [net.officefloor:bom](https://github.com/officefloor/OfficeFloor) from 3.30.2 to 3.31.0.
- [Release notes](https://github.com/officefloor/OfficeFloor/releases)
- [Commits](https://github.com/officefloor/OfficeFloor/commits)

Signed-off-by: dependabot-preview[bot] <[email protected]>

* Bump net.officefloor:bom in /frameworks/Java/officefloor/src

Bumps [net.officefloor:bom](https://github.com/officefloor/OfficeFloor) from 3.31.0 to 3.32.0.
- [Release notes](https://github.com/officefloor/OfficeFloor/releases)
- [Commits](https://github.com/officefloor/OfficeFloor/commits)

Signed-off-by: dependabot-preview[bot] <[email protected]>

* Bump spring-boot-maven-plugin in /frameworks/Java/officefloor/src

Bumps [spring-boot-maven-plugin](https://github.com/spring-projects/spring-boot) from 2.4.2 to 2.4.3.
- [Release notes](https://github.com/spring-projects/spring-boot/releases)
- [Commits](https://github.com/spring-projects/spring-boot/compare/v2.4.2...v2.4.3)

Signed-off-by: dependabot-preview[bot] <[email protected]>

* Bump spring-boot-maven-plugin in /frameworks/Java/officefloor/src

Bumps [spring-boot-maven-plugin](https://github.com/spring-projects/spring-boot) from 2.4.3 to 2.4.5.
- [Release notes](https://github.com/spring-projects/spring-boot/releases)
- [Commits](https://github.com/spring-projects/spring-boot/compare/v2.4.3...v2.4.5)

Signed-off-by: dependabot-preview[bot] <[email protected]>

* Upgrade to GitHub-native Dependabot

* Bump net.officefloor:bom in /frameworks/Java/officefloor/src

Bumps [net.officefloor:bom](https://github.com/officefloor/OfficeFloor) from 3.32.0 to 3.35.0.
- [Release notes](https://github.com/officefloor/OfficeFloor/releases)
- [Commits](https://github.com/officefloor/OfficeFloor/commits/release-3.35.0)

Signed-off-by: dependabot-preview[bot] <[email protected]>

* Bump to OfficeFloor 3.35.0

* Allow bump of all versions

* Vertx server

Also, renaming officefloor-raw to officefloor-r2dbc to make way for
officefloor-sqlclient

* Rename to R2dbc (from raw)

* Bump net.officefloor:bom in /frameworks/Java/officefloor/src

Bumps [net.officefloor:bom](https://github.com/officefloor/OfficeFloor) from 3.35.0 to 3.36.0.
- [Release notes](https://github.com/officefloor/OfficeFloor/releases)
- [Commits](https://github.com/officefloor/OfficeFloor/commits)

Signed-off-by: dependabot[bot] <[email protected]>

* Fixing meta-data

* Can not propagate Dependabot to TechEmpower

* Abstract WoOF from database driver

This will allow introducing Vertx SQL Client

* Fixing db port

* Providing Vertx SQL Client implementation

* Using OfficeFloorVertx for vertx

Allows for tests to reset

* Fixing link in read me

* Reducing repetition in readme

* Swapped OfficeFloor async to use Vertx SQL Client

* Bump spring-boot-maven-plugin in /frameworks/Java/officefloor/src

Bumps [spring-boot-maven-plugin](https://github.com/spring-projects/spring-boot) from 2.4.5 to 2.5.0.
- [Release notes](https://github.com/spring-projects/spring-boot/releases)
- [Commits](https://github.com/spring-projects/spring-boot/compare/v2.4.5...v2.5.0)

Signed-off-by: dependabot[bot] <[email protected]>

* Increasing SQL Client pool size to 512

Also, fixing update to sort to avoid deadlocks

* Removing unnecessary logging

* Removing dependabot configuration

* Improving performance of Vertx

This is by caching queries and using native communication.

Also, adding further performance updates to update test by sorting
updates

* Fixing OfficeFloor-vertx name

* Reducing load on DB callback threads

* Database worker threads relative to number of socket threads

* Further improvements to performance (by less contention)

* Avoid lock on write stream

* Using Guava

* Removing commented out line

* Providing Cache implementation

* Re-enabling thread affinity

* Making R2DBC more resilient

* Adding cached query configuration entries

* Caching runs off World table

* Only require World able

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Daniel 4 years ago
parent
commit
b10ea2627e
32 changed files with 445 additions and 24 deletions
  1. 8 0
      frameworks/Java/officefloor/benchmark_config.json
  2. 8 0
      frameworks/Java/officefloor/config.toml
  3. 6 1
      frameworks/Java/officefloor/src/pom.xml
  4. 4 0
      frameworks/Java/officefloor/src/woof_benchmark/pom.xml
  5. 11 0
      frameworks/Java/officefloor/src/woof_benchmark/src/main/java/net/officefloor/benchmark/CachedWorld.java
  6. 39 0
      frameworks/Java/officefloor/src/woof_benchmark/src/main/java/net/officefloor/benchmark/CachedWorldDataRetriever.java
  7. 23 0
      frameworks/Java/officefloor/src/woof_benchmark/src/main/java/net/officefloor/benchmark/Logic.java
  8. 3 0
      frameworks/Java/officefloor/src/woof_benchmark/src/main/resources/application.objects
  9. 6 2
      frameworks/Java/officefloor/src/woof_benchmark/src/main/resources/application.woof
  10. 4 0
      frameworks/Java/officefloor/src/woof_benchmark_micro/pom.xml
  11. 13 0
      frameworks/Java/officefloor/src/woof_benchmark_micro/src/main/java/net/officefloor/benchmark/CachedWorld.java
  12. 39 0
      frameworks/Java/officefloor/src/woof_benchmark_micro/src/main/java/net/officefloor/benchmark/CachedWorldDataRetriever.java
  13. 23 0
      frameworks/Java/officefloor/src/woof_benchmark_micro/src/main/java/net/officefloor/benchmark/Logic.java
  14. 3 0
      frameworks/Java/officefloor/src/woof_benchmark_micro/src/main/resources/application.objects
  15. 6 2
      frameworks/Java/officefloor/src/woof_benchmark_micro/src/main/resources/application.woof
  16. 4 0
      frameworks/Java/officefloor/src/woof_benchmark_r2dbc/pom.xml
  17. 84 6
      frameworks/Java/officefloor/src/woof_benchmark_r2dbc/src/main/java/net/officefloor/benchmark/R2dbcOfficeFloorMain.java
  18. 4 0
      frameworks/Java/officefloor/src/woof_benchmark_spring/pom.xml
  19. 11 0
      frameworks/Java/officefloor/src/woof_benchmark_spring/src/main/java/net/officefloor/benchmark/CachedWorld.java
  20. 29 0
      frameworks/Java/officefloor/src/woof_benchmark_spring/src/main/java/net/officefloor/benchmark/CachedWorldDataRetriever.java
  21. 0 3
      frameworks/Java/officefloor/src/woof_benchmark_spring/src/main/java/net/officefloor/benchmark/Fortune.java
  22. 23 0
      frameworks/Java/officefloor/src/woof_benchmark_spring/src/main/java/net/officefloor/benchmark/Logic.java
  23. 3 0
      frameworks/Java/officefloor/src/woof_benchmark_spring/src/main/resources/application.objects
  24. 6 0
      frameworks/Java/officefloor/src/woof_benchmark_spring/src/main/resources/application.woof
  25. 6 1
      frameworks/Java/officefloor/src/woof_benchmark_sqlclient/src/main/java/net/officefloor/benchmark/SqlClientOfficeFloorMain.java
  26. 0 4
      frameworks/Java/officefloor/src/woof_benchmark_woof/pom.xml
  27. 42 0
      frameworks/Java/officefloor/src/woof_benchmark_woof/src/main/java/net/officefloor/benchmark/CachedSendResponse.java
  28. 18 0
      frameworks/Java/officefloor/src/woof_benchmark_woof/src/main/java/net/officefloor/benchmark/CachedWorld.java
  29. 5 0
      frameworks/Java/officefloor/src/woof_benchmark_woof/src/main/java/net/officefloor/benchmark/DatabaseOperations.java
  30. 2 1
      frameworks/Java/officefloor/src/woof_benchmark_woof/src/main/java/net/officefloor/benchmark/DatabaseOperationsFactory.java
  31. 0 3
      frameworks/Java/officefloor/src/woof_benchmark_woof/src/main/java/net/officefloor/benchmark/FortunesSendResponse.java
  32. 12 1
      frameworks/Java/officefloor/src/woof_benchmark_woof/src/main/java/net/officefloor/benchmark/RawWoof.java

+ 8 - 0
frameworks/Java/officefloor/benchmark_config.json

@@ -7,6 +7,7 @@
 				"plaintext_url": "/plaintext",
 				"plaintext_url": "/plaintext",
 				"db_url": "/db",
 				"db_url": "/db",
 				"query_url": "/queries?queries=",
 				"query_url": "/queries?queries=",
+				"cached_query_url": "/cached-worlds?count=",
 				"fortune_url": "/fortunes",
 				"fortune_url": "/fortunes",
 				"update_url": "/update?queries=",
 				"update_url": "/update?queries=",
 				"port": 8080,
 				"port": 8080,
@@ -30,6 +31,7 @@
 				"plaintext_url": "/plaintext",
 				"plaintext_url": "/plaintext",
 				"db_url": "/db",
 				"db_url": "/db",
 				"query_url": "/queries?queries=",
 				"query_url": "/queries?queries=",
+				"cached_query_url": "/cached-worlds?count=",
 				"fortune_url": "/fortunes",
 				"fortune_url": "/fortunes",
 				"update_url": "/update?queries=",
 				"update_url": "/update?queries=",
 				"port": 8080,
 				"port": 8080,
@@ -97,6 +99,7 @@
 				"plaintext_url": "/plaintext",
 				"plaintext_url": "/plaintext",
 				"db_url": "/db",
 				"db_url": "/db",
 				"query_url": "/queries?queries=",
 				"query_url": "/queries?queries=",
+				"cached_query_url": "/cached-worlds?count=",
 				"fortune_url": "/fortunes",
 				"fortune_url": "/fortunes",
 				"update_url": "/update?queries=",
 				"update_url": "/update?queries=",
 				"port": 8080,
 				"port": 8080,
@@ -120,6 +123,7 @@
 				"plaintext_url": "/plaintext",
 				"plaintext_url": "/plaintext",
 				"db_url": "/db",
 				"db_url": "/db",
 				"query_url": "/queries?queries=",
 				"query_url": "/queries?queries=",
+				"cached_query_url": "/cached-worlds?count=",
 				"fortune_url": "/fortunes",
 				"fortune_url": "/fortunes",
 				"update_url": "/update?queries=",
 				"update_url": "/update?queries=",
 				"port": 8080,
 				"port": 8080,
@@ -143,6 +147,7 @@
 				"plaintext_url": "/plaintext",
 				"plaintext_url": "/plaintext",
 				"db_url": "/db",
 				"db_url": "/db",
 				"query_url": "/queries?queries=",
 				"query_url": "/queries?queries=",
+				"cached_query_url": "/cached-worlds?count=",
 				"fortune_url": "/fortunes",
 				"fortune_url": "/fortunes",
 				"update_url": "/update?queries=",
 				"update_url": "/update?queries=",
 				"port": 8080,
 				"port": 8080,
@@ -166,6 +171,7 @@
 				"plaintext_url": "/plaintext",
 				"plaintext_url": "/plaintext",
 				"db_url": "/db",
 				"db_url": "/db",
 				"query_url": "/queries?queries=",
 				"query_url": "/queries?queries=",
+				"cached_query_url": "/cached-worlds?count=",
 				"fortune_url": "/fortunes",
 				"fortune_url": "/fortunes",
 				"update_url": "/update?queries=",
 				"update_url": "/update?queries=",
 				"port": 8080,
 				"port": 8080,
@@ -189,6 +195,7 @@
 				"plaintext_url": "/plaintext",
 				"plaintext_url": "/plaintext",
 				"db_url": "/db",
 				"db_url": "/db",
 				"query_url": "/queries?queries=",
 				"query_url": "/queries?queries=",
+				"cached_query_url": "/cached-worlds?count=",
 				"fortune_url": "/fortunes",
 				"fortune_url": "/fortunes",
 				"update_url": "/update?queries=",
 				"update_url": "/update?queries=",
 				"port": 8080,
 				"port": 8080,
@@ -212,6 +219,7 @@
 				"plaintext_url": "/plaintext",
 				"plaintext_url": "/plaintext",
 				"db_url": "/db",
 				"db_url": "/db",
 				"query_url": "/queries?queries=",
 				"query_url": "/queries?queries=",
+				"cached_query_url": "/cached-worlds?count=",
 				"fortune_url": "/fortunes",
 				"fortune_url": "/fortunes",
 				"update_url": "/update?queries=",
 				"update_url": "/update?queries=",
 				"port": 8080,
 				"port": 8080,

+ 8 - 0
frameworks/Java/officefloor/config.toml

@@ -6,6 +6,7 @@ urls.plaintext = "/plaintext"
 urls.json = "/json"
 urls.json = "/json"
 urls.db = "/db"
 urls.db = "/db"
 urls.query = "/queries?queries="
 urls.query = "/queries?queries="
+urls.cached_query = "/cached-worlds?count="
 urls.update = "/update?queries="
 urls.update = "/update?queries="
 urls.fortune = "/fortunes"
 urls.fortune = "/fortunes"
 approach = "Realistic"
 approach = "Realistic"
@@ -23,6 +24,7 @@ urls.plaintext = "/plaintext"
 urls.json = "/json"
 urls.json = "/json"
 urls.db = "/db"
 urls.db = "/db"
 urls.query = "/queries?queries="
 urls.query = "/queries?queries="
+urls.cached_query = "/cached-worlds?count="
 urls.update = "/update?queries="
 urls.update = "/update?queries="
 urls.fortune = "/fortunes"
 urls.fortune = "/fortunes"
 approach = "Realistic"
 approach = "Realistic"
@@ -40,6 +42,7 @@ urls.plaintext = "/plaintext"
 urls.json = "/json"
 urls.json = "/json"
 urls.db = "/db"
 urls.db = "/db"
 urls.query = "/queries?queries="
 urls.query = "/queries?queries="
+urls.cached_query = "/cached-worlds?count="
 urls.update = "/update?queries="
 urls.update = "/update?queries="
 urls.fortune = "/fortunes"
 urls.fortune = "/fortunes"
 approach = "Realistic"
 approach = "Realistic"
@@ -57,6 +60,7 @@ urls.plaintext = "/plaintext"
 urls.json = "/json"
 urls.json = "/json"
 urls.db = "/db"
 urls.db = "/db"
 urls.query = "/queries?queries="
 urls.query = "/queries?queries="
+urls.cached_query = "/cached-worlds?count="
 urls.update = "/update?queries="
 urls.update = "/update?queries="
 urls.fortune = "/fortunes"
 urls.fortune = "/fortunes"
 approach = "Realistic"
 approach = "Realistic"
@@ -74,6 +78,7 @@ urls.plaintext = "/plaintext"
 urls.json = "/json"
 urls.json = "/json"
 urls.db = "/db"
 urls.db = "/db"
 urls.query = "/queries?queries="
 urls.query = "/queries?queries="
+urls.cached_query = "/cached-worlds?count="
 urls.update = "/update?queries="
 urls.update = "/update?queries="
 urls.fortune = "/fortunes"
 urls.fortune = "/fortunes"
 approach = "Realistic"
 approach = "Realistic"
@@ -108,6 +113,7 @@ urls.plaintext = "/plaintext"
 urls.json = "/json"
 urls.json = "/json"
 urls.db = "/db"
 urls.db = "/db"
 urls.query = "/queries?queries="
 urls.query = "/queries?queries="
+urls.cached_query = "/cached-worlds?count="
 urls.update = "/update?queries="
 urls.update = "/update?queries="
 urls.fortune = "/fortunes"
 urls.fortune = "/fortunes"
 approach = "Realistic"
 approach = "Realistic"
@@ -125,6 +131,7 @@ urls.plaintext = "/plaintext"
 urls.json = "/json"
 urls.json = "/json"
 urls.db = "/db"
 urls.db = "/db"
 urls.query = "/queries?queries="
 urls.query = "/queries?queries="
+urls.cached_query = "/cached-worlds?count="
 urls.update = "/update?queries="
 urls.update = "/update?queries="
 urls.fortune = "/fortunes"
 urls.fortune = "/fortunes"
 approach = "Realistic"
 approach = "Realistic"
@@ -142,6 +149,7 @@ urls.plaintext = "/plaintext"
 urls.json = "/json"
 urls.json = "/json"
 urls.db = "/db"
 urls.db = "/db"
 urls.query = "/queries?queries="
 urls.query = "/queries?queries="
+urls.cached_query = "/cached-worlds?count="
 urls.update = "/update?queries="
 urls.update = "/update?queries="
 urls.fortune = "/fortunes"
 urls.fortune = "/fortunes"
 approach = "Realistic"
 approach = "Realistic"

+ 6 - 1
frameworks/Java/officefloor/src/pom.xml

@@ -42,7 +42,7 @@
 			<dependency>
 			<dependency>
 				<groupId>net.officefloor</groupId>
 				<groupId>net.officefloor</groupId>
 				<artifactId>bom</artifactId>
 				<artifactId>bom</artifactId>
-				<version>3.36.0</version>
+				<version>3.37.0</version>
 				<type>pom</type>
 				<type>pom</type>
 				<scope>import</scope>
 				<scope>import</scope>
 			</dependency>
 			</dependency>
@@ -66,6 +66,11 @@
 				<artifactId>compiler</artifactId>
 				<artifactId>compiler</artifactId>
 				<version>0.9.7</version>
 				<version>0.9.7</version>
 			</dependency>
 			</dependency>
+			<dependency>
+				<groupId>com.google.guava</groupId>
+				<artifactId>guava</artifactId>
+				<version>29.0-jre</version>
+			</dependency>
 		</dependencies>
 		</dependencies>
 	</dependencyManagement>
 	</dependencyManagement>
 	<build>
 	<build>

+ 4 - 0
frameworks/Java/officefloor/src/woof_benchmark/pom.xml

@@ -29,6 +29,10 @@
 			<groupId>net.officefloor.persistence</groupId>
 			<groupId>net.officefloor.persistence</groupId>
 			<artifactId>officejpa_hibernate</artifactId>
 			<artifactId>officejpa_hibernate</artifactId>
 		</dependency>
 		</dependency>
+		<dependency>
+			<groupId>net.officefloor.cache</groupId>
+			<artifactId>officecache_constant</artifactId>
+		</dependency>
 		<dependency>
 		<dependency>
 			<groupId>org.projectlombok</groupId>
 			<groupId>org.projectlombok</groupId>
 			<artifactId>lombok</artifactId>
 			<artifactId>lombok</artifactId>

+ 11 - 0
frameworks/Java/officefloor/src/woof_benchmark/src/main/java/net/officefloor/benchmark/CachedWorld.java

@@ -0,0 +1,11 @@
+package net.officefloor.benchmark;
+
+import lombok.Data;
+
+@Data
+public class CachedWorld {
+
+	private final int id;
+
+	private final int randomNumber;
+}

+ 39 - 0
frameworks/Java/officefloor/src/woof_benchmark/src/main/java/net/officefloor/benchmark/CachedWorldDataRetriever.java

@@ -0,0 +1,39 @@
+package net.officefloor.benchmark;
+
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.sql.DataSource;
+
+import net.officefloor.cache.Cache;
+import net.officefloor.cache.constant.ConstantCacheDataRetriever;
+import net.officefloor.plugin.clazz.Dependency;
+
+/**
+ * {@link ConstantCacheDataRetriever} containing polling logic to refresh the
+ * {@link Cache}.
+ * 
+ * @author Daniel Sagenschneider
+ */
+public class CachedWorldDataRetriever implements ConstantCacheDataRetriever<Integer, CachedWorld> {
+
+	private @Dependency DataSource dataSource;
+
+	@Override
+	public Map<Integer, CachedWorld> getData() throws Exception {
+		try (Connection connection = this.dataSource.getConnection()) {
+			Map<Integer, CachedWorld> data = new HashMap<>();
+			ResultSet resultSet = connection.prepareStatement("SELECT id, randomNumber FROM World")
+					.executeQuery();
+			while (resultSet.next()) {
+				int id = resultSet.getInt("id");
+				int randomNumber = resultSet.getInt("randomNumber");
+				data.put(id, new CachedWorld(id, randomNumber));
+			}
+			return data;
+		}
+	}
+
+}

+ 23 - 0
frameworks/Java/officefloor/src/woof_benchmark/src/main/java/net/officefloor/benchmark/Logic.java

@@ -7,6 +7,7 @@ import java.util.concurrent.ThreadLocalRandom;
 import javax.persistence.EntityManager;
 import javax.persistence.EntityManager;
 
 
 import lombok.Data;
 import lombok.Data;
+import net.officefloor.cache.Cache;
 import net.officefloor.web.HttpQueryParameter;
 import net.officefloor.web.HttpQueryParameter;
 import net.officefloor.web.ObjectResponse;
 import net.officefloor.web.ObjectResponse;
 
 
@@ -67,6 +68,28 @@ public class Logic {
 		response.send(worlds);
 		response.send(worlds);
 	}
 	}
 
 
+	// ========== CACHED ==================
+
+	public void cached(@HttpQueryParameter("count") String queries, Cache<Integer, CachedWorld> cache,
+			ObjectResponse<CachedWorld[]> response) {
+		int count = getQueryCount(queries);
+
+		// Set up for unique numbers
+		ThreadLocalRandom random = ThreadLocalRandom.current();
+
+		// Obtain the list of cached worlds
+		CachedWorld[] worlds = new CachedWorld[count];
+		for (int i = 0; i < worlds.length; i++) {
+
+			// Obtain unique identifier
+			int randomNumber = random.nextInt(1, 10001);
+
+			// Obtain the cached world
+			worlds[i] = cache.get(randomNumber);
+		}
+		response.send(worlds);
+	}
+
 	// =========== UPDATES ===================
 	// =========== UPDATES ===================
 
 
 	public void update(@HttpQueryParameter("queries") String queries, EntityManager entityManager,
 	public void update(@HttpQueryParameter("queries") String queries, EntityManager entityManager,

+ 3 - 0
frameworks/Java/officefloor/src/woof_benchmark/src/main/resources/application.objects

@@ -5,6 +5,9 @@
 		<property name="persistence.dependency" value="datasource" />
 		<property name="persistence.dependency" value="datasource" />
 	</managed-object>
 	</managed-object>
 
 
+	<managed-object source="net.officefloor.cache.constant.ConstantCacheManagedObjectSource" />
+	<managed-object class="net.officefloor.benchmark.CachedWorldDataRetriever" /> 
+
 	<managed-object source="net.officefloor.jdbc.DataSourceManagedObjectSource">
 	<managed-object source="net.officefloor.jdbc.DataSourceManagedObjectSource">
 		<property-file path="datasource.properties" />
 		<property-file path="datasource.properties" />
 	</managed-object>
 	</managed-object>

+ 6 - 2
frameworks/Java/officefloor/src/woof_benchmark/src/main/resources/application.woof

@@ -12,6 +12,9 @@
     <http-continuation path="/update" secure="false" x="80" y="275">
     <http-continuation path="/update" secure="false" x="80" y="275">
       <section name="Logic" input="update"/>
       <section name="Logic" input="update"/>
     </http-continuation>
     </http-continuation>
+    <http-continuation path="/cached-worlds" secure="false" x="81" y="329">
+      <section name="Logic" input="cached"/>
+    </http-continuation>
   </http-continuations>
   </http-continuations>
   <http-inputs>
   <http-inputs>
   </http-inputs>
   </http-inputs>
@@ -23,14 +26,15 @@
   </templates>
   </templates>
   <sections>
   <sections>
     <section name="Logic" source="net.officefloor.plugin.section.clazz.ClassSectionSource" location="net.officefloor.benchmark.Logic" x="281" y="140">
     <section name="Logic" source="net.officefloor.plugin.section.clazz.ClassSectionSource" location="net.officefloor.benchmark.Logic" x="281" y="140">
+      <input name="cached" parameter-type=""/>
       <input name="db" parameter-type=""/>
       <input name="db" parameter-type=""/>
-      <input name="getEntry" parameter-type="net.officefloor.benchmark.Logic$GetEntry"/>
       <input name="json" parameter-type=""/>
       <input name="json" parameter-type=""/>
       <input name="queries" parameter-type=""/>
       <input name="queries" parameter-type=""/>
       <input name="update" parameter-type=""/>
       <input name="update" parameter-type=""/>
-      <input name="updateEntry" parameter-type="net.officefloor.benchmark.Logic$UpdateEntry"/>
     </section>
     </section>
   </sections>
   </sections>
+  <procedures>
+  </procedures>
   <securities>
   <securities>
   </securities>
   </securities>
   <governances>
   <governances>

+ 4 - 0
frameworks/Java/officefloor/src/woof_benchmark_micro/pom.xml

@@ -25,6 +25,10 @@
 			<groupId>net.officefloor.persistence</groupId>
 			<groupId>net.officefloor.persistence</groupId>
 			<artifactId>officejdbc_hikari</artifactId>
 			<artifactId>officejdbc_hikari</artifactId>
 		</dependency>
 		</dependency>
+		<dependency>
+			<groupId>net.officefloor.cache</groupId>
+			<artifactId>officecache_constant</artifactId>
+		</dependency>
 		<dependency>
 		<dependency>
 			<groupId>org.projectlombok</groupId>
 			<groupId>org.projectlombok</groupId>
 			<artifactId>lombok</artifactId>
 			<artifactId>lombok</artifactId>

+ 13 - 0
frameworks/Java/officefloor/src/woof_benchmark_micro/src/main/java/net/officefloor/benchmark/CachedWorld.java

@@ -0,0 +1,13 @@
+package net.officefloor.benchmark;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+
+@Data
+@AllArgsConstructor
+public class CachedWorld {
+
+	private int id;
+
+	private int randomNumber;
+}

+ 39 - 0
frameworks/Java/officefloor/src/woof_benchmark_micro/src/main/java/net/officefloor/benchmark/CachedWorldDataRetriever.java

@@ -0,0 +1,39 @@
+package net.officefloor.benchmark;
+
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.sql.DataSource;
+
+import net.officefloor.cache.Cache;
+import net.officefloor.cache.constant.ConstantCacheDataRetriever;
+import net.officefloor.plugin.clazz.Dependency;
+
+/**
+ * {@link ConstantCacheDataRetriever} containing polling logic to refresh the
+ * {@link Cache}.
+ * 
+ * @author Daniel Sagenschneider
+ */
+public class CachedWorldDataRetriever implements ConstantCacheDataRetriever<Integer, CachedWorld> {
+
+	private @Dependency DataSource dataSource;
+
+	@Override
+	public Map<Integer, CachedWorld> getData() throws Exception {
+		try (Connection connection = this.dataSource.getConnection()) {
+			Map<Integer, CachedWorld> data = new HashMap<>();
+			ResultSet resultSet = connection.prepareStatement("SELECT id, randomNumber FROM World")
+					.executeQuery();
+			while (resultSet.next()) {
+				int id = resultSet.getInt("id");
+				int randomNumber = resultSet.getInt("randomNumber");
+				data.put(id, new CachedWorld(id, randomNumber));
+			}
+			return data;
+		}
+	}
+
+}

+ 23 - 0
frameworks/Java/officefloor/src/woof_benchmark_micro/src/main/java/net/officefloor/benchmark/Logic.java

@@ -16,6 +16,7 @@ import javax.sql.DataSource;
 import org.apache.commons.text.StringEscapeUtils;
 import org.apache.commons.text.StringEscapeUtils;
 
 
 import lombok.Data;
 import lombok.Data;
+import net.officefloor.cache.Cache;
 import net.officefloor.server.http.HttpHeaderValue;
 import net.officefloor.server.http.HttpHeaderValue;
 import net.officefloor.server.http.HttpResponse;
 import net.officefloor.server.http.HttpResponse;
 import net.officefloor.server.http.ServerHttpConnection;
 import net.officefloor.server.http.ServerHttpConnection;
@@ -77,6 +78,28 @@ public class Logic {
 		}
 		}
 	}
 	}
 
 
+	// ========== CACHED ==================
+
+	public void cached(@HttpQueryParameter("count") String queries, Cache<Integer, CachedWorld> cache,
+			ObjectResponse<CachedWorld[]> response) {
+		int count = getQueryCount(queries);
+
+		// Set up for unique numbers
+		ThreadLocalRandom random = ThreadLocalRandom.current();
+
+		// Obtain the list of cached worlds
+		CachedWorld[] worlds = new CachedWorld[count];
+		for (int i = 0; i < worlds.length; i++) {
+
+			// Obtain unique identifier
+			int randomNumber = random.nextInt(1, 10001);
+
+			// Obtain the cached world
+			worlds[i] = cache.get(randomNumber);
+		}
+		response.send(worlds);
+	}
+
 	// =========== UPDATES ===================
 	// =========== UPDATES ===================
 
 
 	public void update(@HttpQueryParameter("queries") String queries, DataSource dataSource,
 	public void update(@HttpQueryParameter("queries") String queries, DataSource dataSource,

+ 3 - 0
frameworks/Java/officefloor/src/woof_benchmark_micro/src/main/resources/application.objects

@@ -4,4 +4,7 @@
 		<property-file path="datasource.properties" />
 		<property-file path="datasource.properties" />
 	</managed-object>
 	</managed-object>
 
 
+	<managed-object source="net.officefloor.cache.constant.ConstantCacheManagedObjectSource" />
+	<managed-object class="net.officefloor.benchmark.CachedWorldDataRetriever" /> 
+
 </objects>
 </objects>

+ 6 - 2
frameworks/Java/officefloor/src/woof_benchmark_micro/src/main/resources/application.woof

@@ -1,5 +1,8 @@
 <woof>
 <woof>
   <http-continuations>
   <http-continuations>
+    <http-continuation path="/cached-worlds" secure="false" x="82" y="370">
+      <section name="Logic" input="cached"/>
+    </http-continuation>
     <http-continuation path="/db" secure="false" x="87" y="172">
     <http-continuation path="/db" secure="false" x="87" y="172">
       <section name="Logic" input="db"/>
       <section name="Logic" input="db"/>
     </http-continuation>
     </http-continuation>
@@ -24,15 +27,16 @@
   </templates>
   </templates>
   <sections>
   <sections>
     <section name="Logic" source="net.officefloor.plugin.section.clazz.ClassSectionSource" location="net.officefloor.benchmark.Logic" x="281" y="140">
     <section name="Logic" source="net.officefloor.plugin.section.clazz.ClassSectionSource" location="net.officefloor.benchmark.Logic" x="281" y="140">
+      <input name="cached" parameter-type=""/>
       <input name="db" parameter-type=""/>
       <input name="db" parameter-type=""/>
       <input name="fortunes" parameter-type=""/>
       <input name="fortunes" parameter-type=""/>
-      <input name="getEntry" parameter-type="net.officefloor.benchmark.Logic$GetEntry"/>
       <input name="json" parameter-type=""/>
       <input name="json" parameter-type=""/>
       <input name="queries" parameter-type=""/>
       <input name="queries" parameter-type=""/>
       <input name="update" parameter-type=""/>
       <input name="update" parameter-type=""/>
-      <input name="updateEntry" parameter-type="net.officefloor.benchmark.Logic$UpdateEntry"/>
     </section>
     </section>
   </sections>
   </sections>
+  <procedures>
+  </procedures>
   <securities>
   <securities>
   </securities>
   </securities>
   <governances>
   <governances>

+ 4 - 0
frameworks/Java/officefloor/src/woof_benchmark_r2dbc/pom.xml

@@ -21,6 +21,10 @@
 			<groupId>io.r2dbc</groupId>
 			<groupId>io.r2dbc</groupId>
 			<artifactId>r2dbc-pool</artifactId>
 			<artifactId>r2dbc-pool</artifactId>
 		</dependency>
 		</dependency>
+		<dependency>
+			<groupId>net.officefloor.cache</groupId>
+			<artifactId>officecache_constant</artifactId>
+		</dependency>
 	</dependencies>
 	</dependencies>
 	<build>
 	<build>
 		<plugins>
 		<plugins>

+ 84 - 6
frameworks/Java/officefloor/src/woof_benchmark_r2dbc/src/main/java/net/officefloor/benchmark/R2dbcOfficeFloorMain.java

@@ -1,16 +1,25 @@
 package net.officefloor.benchmark;
 package net.officefloor.benchmark;
 
 
 import java.util.Collections;
 import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
 import java.util.concurrent.Executor;
 import java.util.concurrent.Executor;
 import java.util.concurrent.ThreadLocalRandom;
 import java.util.concurrent.ThreadLocalRandom;
 
 
 import io.netty.channel.unix.Socket;
 import io.netty.channel.unix.Socket;
 import io.r2dbc.pool.PoolingConnectionFactoryProvider;
 import io.r2dbc.pool.PoolingConnectionFactoryProvider;
+import io.r2dbc.postgresql.api.PostgresqlException;
 import io.r2dbc.spi.Batch;
 import io.r2dbc.spi.Batch;
 import io.r2dbc.spi.Connection;
 import io.r2dbc.spi.Connection;
 import io.r2dbc.spi.ConnectionFactories;
 import io.r2dbc.spi.ConnectionFactories;
 import io.r2dbc.spi.ConnectionFactory;
 import io.r2dbc.spi.ConnectionFactory;
 import io.r2dbc.spi.ConnectionFactoryOptions;
 import io.r2dbc.spi.ConnectionFactoryOptions;
+import net.officefloor.cache.Cache;
+import net.officefloor.cache.constant.ConstantCacheManagedObjectSource;
+import net.officefloor.frame.api.managedobject.ManagedObject;
+import net.officefloor.frame.util.ManagedObjectSourceStandAlone;
+import net.officefloor.frame.util.ManagedObjectUserStandAlone;
+import net.officefloor.plugin.managedobject.poll.StatePollContext;
 import net.officefloor.server.RequestHandler;
 import net.officefloor.server.RequestHandler;
 import net.officefloor.server.http.parse.HttpRequestParser;
 import net.officefloor.server.http.parse.HttpRequestParser;
 import reactor.core.publisher.Flux;
 import reactor.core.publisher.Flux;
@@ -38,7 +47,7 @@ public class R2dbcOfficeFloorMain implements DatabaseOperations {
 	/**
 	/**
 	 * Run application.
 	 * Run application.
 	 */
 	 */
-	public static void main(String[] args) throws Exception {
+	public static void main(String[] args) throws Throwable {
 
 
 		// Increase the buffer size (note: too high and cause OOM issues)
 		// Increase the buffer size (note: too high and cause OOM issues)
 		System.setProperty("reactor.bufferSize.small", String.valueOf(QUERY_BUFFER_SIZE));
 		System.setProperty("reactor.bufferSize.small", String.valueOf(QUERY_BUFFER_SIZE));
@@ -58,6 +67,11 @@ public class R2dbcOfficeFloorMain implements DatabaseOperations {
 	 */
 	 */
 	private final ThreadLocal<Connection[]> threadLocalConnections;
 	private final ThreadLocal<Connection[]> threadLocalConnections;
 
 
+	/**
+	 * {@link Cache} of {@link CachedWorld}.
+	 */
+	private final Cache<Integer, CachedWorld> cache;
+
 	/**
 	/**
 	 * Instantiate.
 	 * Instantiate.
 	 * 
 	 * 
@@ -68,8 +82,9 @@ public class R2dbcOfficeFloorMain implements DatabaseOperations {
 	 * @param username    Username.
 	 * @param username    Username.
 	 * @param password    Password.
 	 * @param password    Password.
 	 */
 	 */
+	@SuppressWarnings("unchecked")
 	public R2dbcOfficeFloorMain(int socketCount, String server, int port, String database, String username,
 	public R2dbcOfficeFloorMain(int socketCount, String server, int port, String database, String username,
-			String password) {
+			String password) throws Throwable {
 
 
 		// Must have enough connection capacity for initial load (+1 for rounding)
 		// Must have enough connection capacity for initial load (+1 for rounding)
 		int requiredConnectionsPerSocket = (QUERY_LOAD_CAPACITY / (socketCount * QUERY_BUFFER_SIZE)) + 1;
 		int requiredConnectionsPerSocket = (QUERY_LOAD_CAPACITY / (socketCount * QUERY_BUFFER_SIZE)) + 1;
@@ -99,6 +114,48 @@ public class R2dbcOfficeFloorMain implements DatabaseOperations {
 				return connections;
 				return connections;
 			}
 			}
 		};
 		};
+
+		// Provide the cache
+		ManagedObjectSourceStandAlone source = new ManagedObjectSourceStandAlone();
+		source.registerInvokeProcessServicer(0, (processIndex, parameter, managedObject) -> {
+
+			// Poll database for cached data
+			StatePollContext<Map<Integer, CachedWorld>> pollContext = (StatePollContext<Map<Integer, CachedWorld>>) parameter;
+			Map<Integer, CachedWorld> data = new HashMap<>();
+			try {
+				Flux.from(connectionFactory.create()).flatMap((connection) -> {
+					return Flux.from(connection.createStatement("SELECT ID, RANDOMNUMBER FROM WORLD").execute())
+							.flatMap(result -> Flux.from(result.map((row, metadata) -> {
+								Integer id = row.get(0, Integer.class);
+								Integer randomNumber = row.get(1, Integer.class);
+								CachedWorld cachedWorld = new CachedWorld(id, randomNumber);
+								data.put(id, cachedWorld);
+								return cachedWorld;
+							}))).last().flatMap(ignore -> Mono.from(connection.close()));
+				}).blockLast();
+				pollContext.setNextState(data, -1, null);
+			} catch (Exception ex) {
+			}
+		});
+		ManagedObject cacheMo = new ManagedObjectUserStandAlone()
+				.sourceManagedObject(source.loadManagedObjectSource(ConstantCacheManagedObjectSource.class));
+		this.cache = (Cache<Integer, CachedWorld>) cacheMo.getObject();
+	}
+
+	public void sendDatabaseError(Throwable failure, AbstractSendResponse response) {
+
+		// Handle issue of prepared statement not found
+		// (seems unsafe memory issue in R2DBC that occurs during start then stops)
+		if (failure instanceof PostgresqlException) {
+			PostgresqlException postgresqlException = (PostgresqlException) failure;
+			if ("26000".equals(postgresqlException.getErrorDetails().getCode())) {
+				// Prepared statement not existing
+				response.sendError(503); // consider overloaded in connection setup during warm up
+			}
+		}
+
+		// Just send the failure
+		response.sendError(failure);
 	}
 	}
 
 
 	/*
 	/*
@@ -137,7 +194,7 @@ public class R2dbcOfficeFloorMain implements DatabaseOperations {
 				}))).publishOn(conn.writeScheduler).subscribe(world -> {
 				}))).publishOn(conn.writeScheduler).subscribe(world -> {
 					sender.sendDb(world);
 					sender.sendDb(world);
 				}, error -> {
 				}, error -> {
-					sender.sendError(error);
+					this.sendDatabaseError(error, sender);
 				}, () -> {
 				}, () -> {
 					conn.processed(1);
 					conn.processed(1);
 				});
 				});
@@ -164,7 +221,7 @@ public class R2dbcOfficeFloorMain implements DatabaseOperations {
 				}))).collectList().publishOn(conn.writeScheduler).subscribe(worlds -> {
 				}))).collectList().publishOn(conn.writeScheduler).subscribe(worlds -> {
 					sender.sendQueries(worlds.toArray(World[]::new));
 					sender.sendQueries(worlds.toArray(World[]::new));
 				}, error -> {
 				}, error -> {
-					sender.sendError(error);
+					this.sendDatabaseError(error, sender);
 				}, () -> {
 				}, () -> {
 					conn.processed(queryCount);
 					conn.processed(queryCount);
 				});
 				});
@@ -189,7 +246,7 @@ public class R2dbcOfficeFloorMain implements DatabaseOperations {
 				}))).collectList().publishOn(conn.writeScheduler).subscribe(fortunes -> {
 				}))).collectList().publishOn(conn.writeScheduler).subscribe(fortunes -> {
 					sender.sendFortunes(fortunes);
 					sender.sendFortunes(fortunes);
 				}, error -> {
 				}, error -> {
-					sender.sendError(error);
+					this.sendDatabaseError(error, sender);
 				}, () -> {
 				}, () -> {
 					conn.processed(1);
 					conn.processed(1);
 				});
 				});
@@ -233,12 +290,33 @@ public class R2dbcOfficeFloorMain implements DatabaseOperations {
 				}).publishOn(conn.writeScheduler).subscribe(worlds -> {
 				}).publishOn(conn.writeScheduler).subscribe(worlds -> {
 					sender.sendUpdate(worlds.toArray(World[]::new));
 					sender.sendUpdate(worlds.toArray(World[]::new));
 				}, error -> {
 				}, error -> {
-					sender.sendError(error);
+					this.sendDatabaseError(error, sender);
 				}, () -> {
 				}, () -> {
 					conn.processed(executeQueryCount);
 					conn.processed(executeQueryCount);
 				});
 				});
 	}
 	}
 
 
+	@Override
+	public void cached(int queryCount, CachedSendResponse sender) {
+
+		// Set up for unique numbers
+		ThreadLocalRandom random = ThreadLocalRandom.current();
+
+		// Obtain the list of cached worlds
+		CachedWorld[] cachedWorlds = new CachedWorld[queryCount];
+		for (int i = 0; i < cachedWorlds.length; i++) {
+
+			// Obtain unique identifier
+			int randomNumber = random.nextInt(1, 10001);
+
+			// Obtain the cached world
+			cachedWorlds[i] = cache.get(randomNumber);
+		}
+
+		// Send cached worlds
+		sender.sendCached(cachedWorlds);
+	}
+
 	private static class RateLimit {
 	private static class RateLimit {
 
 
 		private final RateLimitedConnection[] rateLimitedConnections;
 		private final RateLimitedConnection[] rateLimitedConnections;

+ 4 - 0
frameworks/Java/officefloor/src/woof_benchmark_spring/pom.xml

@@ -28,6 +28,10 @@
 			<groupId>net.officefloor.persistence</groupId>
 			<groupId>net.officefloor.persistence</groupId>
 			<artifactId>officejdbc_postgresql</artifactId>
 			<artifactId>officejdbc_postgresql</artifactId>
 		</dependency>
 		</dependency>
+		<dependency>
+			<groupId>net.officefloor.cache</groupId>
+			<artifactId>officecache_constant</artifactId>
+		</dependency>
 		<dependency>
 		<dependency>
 			<groupId>org.projectlombok</groupId>
 			<groupId>org.projectlombok</groupId>
 			<artifactId>lombok</artifactId>
 			<artifactId>lombok</artifactId>

+ 11 - 0
frameworks/Java/officefloor/src/woof_benchmark_spring/src/main/java/net/officefloor/benchmark/CachedWorld.java

@@ -0,0 +1,11 @@
+package net.officefloor.benchmark;
+
+import lombok.Data;
+
+@Data
+public class CachedWorld {
+
+	private final int id;
+
+	private final int randomNumber;
+}

+ 29 - 0
frameworks/Java/officefloor/src/woof_benchmark_spring/src/main/java/net/officefloor/benchmark/CachedWorldDataRetriever.java

@@ -0,0 +1,29 @@
+package net.officefloor.benchmark;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import net.officefloor.cache.Cache;
+import net.officefloor.cache.constant.ConstantCacheDataRetriever;
+import net.officefloor.plugin.clazz.Dependency;
+
+/**
+ * {@link ConstantCacheDataRetriever} containing polling logic to refresh the
+ * {@link Cache}.
+ * 
+ * @author Daniel Sagenschneider
+ */
+public class CachedWorldDataRetriever implements ConstantCacheDataRetriever<Integer, CachedWorld> {
+
+	private @Dependency WorldRepository repository;
+
+	@Override
+	public Map<Integer, CachedWorld> getData() throws Exception {
+		Map<Integer, CachedWorld> data = new HashMap<>();
+		for (World world : this.repository.findAll()) {
+			data.put(world.getId(), new CachedWorld(world.getId(), world.getRandomNumber()));
+		}
+		return data;
+	}
+
+}

+ 0 - 3
frameworks/Java/officefloor/src/woof_benchmark_spring/src/main/java/net/officefloor/benchmark/Fortune.java

@@ -18,7 +18,4 @@ public class Fortune {
 
 
 	private String message;
 	private String message;
 	
 	
-	public String getMessage() {
-		return this.message;
-	}
 }
 }

+ 23 - 0
frameworks/Java/officefloor/src/woof_benchmark_spring/src/main/java/net/officefloor/benchmark/Logic.java

@@ -5,6 +5,7 @@ import java.util.Set;
 import java.util.concurrent.ThreadLocalRandom;
 import java.util.concurrent.ThreadLocalRandom;
 
 
 import lombok.Data;
 import lombok.Data;
+import net.officefloor.cache.Cache;
 import net.officefloor.web.HttpQueryParameter;
 import net.officefloor.web.HttpQueryParameter;
 import net.officefloor.web.ObjectResponse;
 import net.officefloor.web.ObjectResponse;
 
 
@@ -65,6 +66,28 @@ public class Logic {
 		response.send(worlds);
 		response.send(worlds);
 	}
 	}
 
 
+	// ========== CACHED ==================
+
+	public void cached(@HttpQueryParameter("count") String queries, Cache<Integer, CachedWorld> cache,
+			ObjectResponse<CachedWorld[]> response) {
+		int count = getQueryCount(queries);
+
+		// Set up for unique numbers
+		ThreadLocalRandom random = ThreadLocalRandom.current();
+
+		// Obtain the list of cached worlds
+		CachedWorld[] worlds = new CachedWorld[count];
+		for (int i = 0; i < worlds.length; i++) {
+
+			// Obtain unique identifier
+			int randomNumber = random.nextInt(1, 10001);
+
+			// Obtain the cached world
+			worlds[i] = cache.get(randomNumber);
+		}
+		response.send(worlds);
+	}
+
 	// =========== UPDATES ===================
 	// =========== UPDATES ===================
 
 
 	public void update(@HttpQueryParameter("queries") String queries, WorldRepository repository,
 	public void update(@HttpQueryParameter("queries") String queries, WorldRepository repository,

+ 3 - 0
frameworks/Java/officefloor/src/woof_benchmark_spring/src/main/resources/application.objects

@@ -4,4 +4,7 @@
 		<property name="configuration.class" value="net.officefloor.benchmark.SpringSetup" />
 		<property name="configuration.class" value="net.officefloor.benchmark.SpringSetup" />
 	</supplier>
 	</supplier>
 
 
+	<managed-object source="net.officefloor.cache.constant.ConstantCacheManagedObjectSource" />
+	<managed-object class="net.officefloor.benchmark.CachedWorldDataRetriever" /> 
+
 </objects>
 </objects>

+ 6 - 0
frameworks/Java/officefloor/src/woof_benchmark_spring/src/main/resources/application.woof

@@ -1,5 +1,8 @@
 <woof>
 <woof>
   <http-continuations>
   <http-continuations>
+    <http-continuation path="/cached-worlds" secure="false" x="37" y="264">
+      <section name="Logic" input="cached"/>
+    </http-continuation>
     <http-continuation path="/db" secure="false" x="84" y="112">
     <http-continuation path="/db" secure="false" x="84" y="112">
       <section name="Logic" input="db"/>
       <section name="Logic" input="db"/>
     </http-continuation>
     </http-continuation>
@@ -23,12 +26,15 @@
   </templates>
   </templates>
   <sections>
   <sections>
     <section name="Logic" source="net.officefloor.plugin.section.clazz.ClassSectionSource" location="net.officefloor.benchmark.Logic" x="258" y="122">
     <section name="Logic" source="net.officefloor.plugin.section.clazz.ClassSectionSource" location="net.officefloor.benchmark.Logic" x="258" y="122">
+      <input name="cached" parameter-type=""/>
       <input name="db" parameter-type=""/>
       <input name="db" parameter-type=""/>
       <input name="json" parameter-type=""/>
       <input name="json" parameter-type=""/>
       <input name="queries" parameter-type=""/>
       <input name="queries" parameter-type=""/>
       <input name="update" parameter-type=""/>
       <input name="update" parameter-type=""/>
     </section>
     </section>
   </sections>
   </sections>
+  <procedures>
+  </procedures>
   <securities>
   <securities>
   </securities>
   </securities>
   <governances>
   <governances>

+ 6 - 1
frameworks/Java/officefloor/src/woof_benchmark_sqlclient/src/main/java/net/officefloor/benchmark/SqlClientOfficeFloorMain.java

@@ -29,7 +29,7 @@ public class SqlClientOfficeFloorMain implements DatabaseOperations {
 	/**
 	/**
 	 * Run application.
 	 * Run application.
 	 */
 	 */
-	public static void main(String[] args) throws Exception {
+	public static void main(String[] args) throws Throwable {
 		RawWoof.run(args, (socketCount, server, port, database, username,
 		RawWoof.run(args, (socketCount, server, port, database, username,
 				password) -> new SqlClientOfficeFloorMain(socketCount, server, port, database, username, password));
 				password) -> new SqlClientOfficeFloorMain(socketCount, server, port, database, username, password));
 	}
 	}
@@ -201,4 +201,9 @@ public class SqlClientOfficeFloorMain implements DatabaseOperations {
 		}
 		}
 	}
 	}
 
 
+	@Override
+	public void cached(int updateCount, CachedSendResponse sender) {
+		throw new UnsupportedOperationException("/cached-worlds test not supported");
+	}
+
 }
 }

+ 0 - 4
frameworks/Java/officefloor/src/woof_benchmark_woof/pom.xml

@@ -8,9 +8,6 @@
 		<version>1.0.0</version>
 		<version>1.0.0</version>
 	</parent>
 	</parent>
 	<artifactId>woof_benchmark_woof</artifactId>
 	<artifactId>woof_benchmark_woof</artifactId>
-	<properties>
-		<guava-version>29.0-jre</guava-version>
-	</properties>
 	<dependencies>
 	<dependencies>
 		<dependency>
 		<dependency>
 			<groupId>net.officefloor.web</groupId>
 			<groupId>net.officefloor.web</groupId>
@@ -37,7 +34,6 @@
 		<dependency>
 		<dependency>
 			<groupId>com.google.guava</groupId>
 			<groupId>com.google.guava</groupId>
 			<artifactId>guava</artifactId>
 			<artifactId>guava</artifactId>
-			<version>${guava-version}</version>
 		</dependency>
 		</dependency>
 	</dependencies>
 	</dependencies>
 </project>
 </project>

+ 42 - 0
frameworks/Java/officefloor/src/woof_benchmark_woof/src/main/java/net/officefloor/benchmark/CachedSendResponse.java

@@ -0,0 +1,42 @@
+package net.officefloor.benchmark;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.CancelledKeyException;
+import java.nio.channels.ClosedChannelException;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import net.officefloor.server.RequestHandler;
+import net.officefloor.server.http.HttpResponse;
+import net.officefloor.server.http.impl.ProcessAwareServerHttpConnectionManagedObject;
+import net.officefloor.server.http.parse.HttpRequestParser;
+
+/**
+ * Sends the Queries response.
+ * 
+ * @author Daniel Sagenschneider
+ */
+public class CachedSendResponse extends AbstractSendResponse {
+
+	public CachedSendResponse(RequestHandler<HttpRequestParser> requestHandler,
+			ProcessAwareServerHttpConnectionManagedObject<ByteBuffer> connection, ObjectMapper objectMapper) {
+		super(requestHandler, connection, objectMapper);
+	}
+
+	public void sendCached(CachedWorld[] cachedWorlds) {
+		this.requestHandler.execute(() -> {
+			try {
+				HttpResponse response = this.connection.getResponse();
+				response.setContentType(APPLICATION_JSON, null);
+				this.objectMapper.writeValue(response.getEntityWriter(), cachedWorlds);
+				send(this.connection);
+			} catch (CancelledKeyException | ClosedChannelException ex) {
+				// Ignore as disconnecting client
+			} catch (IOException ex) {
+				ex.printStackTrace();
+			}
+		});
+	}
+
+}

+ 18 - 0
frameworks/Java/officefloor/src/woof_benchmark_woof/src/main/java/net/officefloor/benchmark/CachedWorld.java

@@ -0,0 +1,18 @@
+package net.officefloor.benchmark;
+
+/**
+ * Cached world response.
+ * 
+ * @author Daniel Sagenschneider
+ */
+public class CachedWorld {
+
+	public final int id;
+
+	public final int randomNumber;
+
+	public CachedWorld(int id, int randomNumber) {
+		this.id = id;
+		this.randomNumber = randomNumber;
+	}
+}

+ 5 - 0
frameworks/Java/officefloor/src/woof_benchmark_woof/src/main/java/net/officefloor/benchmark/DatabaseOperations.java

@@ -38,4 +38,9 @@ public interface DatabaseOperations {
 	 */
 	 */
 	void update(int updateCount, UpdateSendResponse sender);
 	void update(int updateCount, UpdateSendResponse sender);
 
 
+	/**
+	 * Undertakes the cached.
+	 */
+	void cached(int queryCount, CachedSendResponse sender);
+
 }
 }

+ 2 - 1
frameworks/Java/officefloor/src/woof_benchmark_woof/src/main/java/net/officefloor/benchmark/DatabaseOperationsFactory.java

@@ -19,8 +19,9 @@ public interface DatabaseOperationsFactory {
 	 * @param username    Username.
 	 * @param username    Username.
 	 * @param password    Password.
 	 * @param password    Password.
 	 * @return {@link DatabaseOperations}.
 	 * @return {@link DatabaseOperations}.
+	 * @throws Throwable If fails to create {@link DatabaseOperations}.
 	 */
 	 */
 	DatabaseOperations createDatabaseOperations(int socketCount, String server, int port, String database,
 	DatabaseOperations createDatabaseOperations(int socketCount, String server, int port, String database,
-			String username, String password);
+			String username, String password) throws Throwable;
 
 
 }
 }

+ 0 - 3
frameworks/Java/officefloor/src/woof_benchmark_woof/src/main/java/net/officefloor/benchmark/FortunesSendResponse.java

@@ -9,8 +9,6 @@ import java.util.Collections;
 import java.util.Comparator;
 import java.util.Comparator;
 import java.util.List;
 import java.util.List;
 
 
-import org.apache.commons.text.StringEscapeUtils;
-
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.google.common.escape.Escaper;
 import com.google.common.escape.Escaper;
 import com.google.common.html.HtmlEscapers;
 import com.google.common.html.HtmlEscapers;
@@ -22,7 +20,6 @@ import net.officefloor.server.http.ServerHttpConnection;
 import net.officefloor.server.http.impl.ProcessAwareServerHttpConnectionManagedObject;
 import net.officefloor.server.http.impl.ProcessAwareServerHttpConnectionManagedObject;
 import net.officefloor.server.http.parse.HttpRequestParser;
 import net.officefloor.server.http.parse.HttpRequestParser;
 import net.officefloor.server.stream.ServerOutputStream;
 import net.officefloor.server.stream.ServerOutputStream;
-import net.officefloor.server.stream.ServerWriter;
 
 
 /**
 /**
  * Sends the Fortunes response.
  * Sends the Fortunes response.

+ 12 - 1
frameworks/Java/officefloor/src/woof_benchmark_woof/src/main/java/net/officefloor/benchmark/RawWoof.java

@@ -79,7 +79,7 @@ public abstract class RawWoof {
 	 * @param args              Command line arguments.
 	 * @param args              Command line arguments.
 	 * @param operationsFactory {@link DatabaseOperationsFactory}.
 	 * @param operationsFactory {@link DatabaseOperationsFactory}.
 	 */
 	 */
-	public static void run(String[] args, DatabaseOperationsFactory operationsFactory) throws Exception {
+	public static void run(String[] args, DatabaseOperationsFactory operationsFactory) throws Throwable {
 
 
 		// Obtain the port from properties
 		// Obtain the port from properties
 		int port = args.length > 0 ? Integer.parseInt(args[0]) : 8080;
 		int port = args.length > 0 ? Integer.parseInt(args[0]) : 8080;
@@ -147,6 +147,8 @@ public abstract class RawWoof {
 
 
 		private static final String UPDATE_PATH_PREFIX = "/update?queries=";
 		private static final String UPDATE_PATH_PREFIX = "/update?queries=";
 
 
+		private static final String CACHED_PATH_PREFIX = "/cached-worlds?count=";
+
 		/**
 		/**
 		 * <code>Date</code> {@link HttpHeaderValue}.
 		 * <code>Date</code> {@link HttpHeaderValue}.
 		 */
 		 */
@@ -298,6 +300,15 @@ public abstract class RawWoof {
 					this.databaseOperations.update(queryCount, new UpdateSendResponse(
 					this.databaseOperations.update(queryCount, new UpdateSendResponse(
 							this.threadLocalRequestHandler.get(), connection, this.objectMapper));
 							this.threadLocalRequestHandler.get(), connection, this.objectMapper));
 
 
+				} else if (requestUri.startsWith(CACHED_PATH_PREFIX)) {
+					// Obtain the number of queries
+					String queriesCountText = requestUri.substring(CACHED_PATH_PREFIX.length());
+					int queryCount = getQueryCount(queriesCountText);
+
+					// Undertake cached
+					this.databaseOperations.cached(queryCount, new CachedSendResponse(
+							this.threadLocalRequestHandler.get(), connection, this.objectMapper));
+
 				} else {
 				} else {
 					// Unknown request
 					// Unknown request
 					response.setStatus(HttpStatus.NOT_FOUND);
 					response.setStatus(HttpStatus.NOT_FOUND);