diff --git a/README.md b/README.md index 0f64e84..915d63a 100644 --- a/README.md +++ b/README.md @@ -8,4 +8,8 @@ * Still in a very early stage * the code is working - * but it remains to be seen if this is a good idea \ No newline at end of file + * but it remains to be seen if this is a good idea + + +-javaagent:/Users/Shautvast/dev/perfix/target/perfix-agent-0.1-SNAPSHOT.jar +-Dperfix.includes=nl.sanderhautvast.contiguous \ No newline at end of file diff --git a/benchmark/pom.xml b/benchmark/pom.xml new file mode 100644 index 0000000..3ef13ce --- /dev/null +++ b/benchmark/pom.xml @@ -0,0 +1,102 @@ + + + 4.0.0 + + com.github.shautvast + contiguous-pom + 1.0-SNAPSHOT + + + benchmark + + + 20 + 20 + UTF-8 + + + + + com.github.shautvast + contiguous-jdbc + 1.0-SNAPSHOT + + + com.github.shautvast + contiguous-jackson + 1.0-SNAPSHOT + + + + org.openjdk.jmh + jmh-core + 1.36 + + + org.openjdk.jmh + jmh-generator-annprocess + 1.36 + provided + + + org.projectlombok + lombok + 1.18.24 + + + com.fasterxml.jackson.core + jackson-databind + 2.15.1 + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.0 + + 9 + 9 + 9 + + + + org.apache.maven.plugins + maven-shade-plugin + 3.2.4 + + + package + + shade + + + benchmark + + + org.openjdk.jmh.Main + + + + + + *:* + + META-INF/*.SF + META-INF/*.DSA + META-INF/*.RSA + + + + + + + + + + + \ No newline at end of file diff --git a/benchmark/src/main/java/com/github/shautvast/contiguous/benchmark/Customer.java b/benchmark/src/main/java/com/github/shautvast/contiguous/benchmark/Customer.java new file mode 100644 index 0000000..2541c9f --- /dev/null +++ b/benchmark/src/main/java/com/github/shautvast/contiguous/benchmark/Customer.java @@ -0,0 +1,20 @@ +package com.github.shautvast.contiguous.benchmark; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/* copied from demo, need common module */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class Customer { + String name; + String email; + String streetname; + int housenumber; + String city; + String country; +} diff --git a/benchmark/src/main/java/com/github/shautvast/contiguous/benchmark/JmhBenchmark.java b/benchmark/src/main/java/com/github/shautvast/contiguous/benchmark/JmhBenchmark.java new file mode 100644 index 0000000..7678dc9 --- /dev/null +++ b/benchmark/src/main/java/com/github/shautvast/contiguous/benchmark/JmhBenchmark.java @@ -0,0 +1,63 @@ +package com.github.shautvast.contiguous.benchmark; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.module.SimpleModule; +import com.github.shautvast.contiguous.ContiguousList; +import com.github.shautvast.contiguous.ListSerializer; +import org.openjdk.jmh.annotations.*; + +import java.util.*; +import java.util.concurrent.TimeUnit; + +@BenchmarkMode(Mode.AverageTime) +@OutputTimeUnit(TimeUnit.NANOSECONDS) +@Fork(value = 1) +public class JmhBenchmark { + + @org.openjdk.jmh.annotations.State(Scope.Benchmark) + public static class State { + //mimick database + final List customers = new ArrayList<>(); + final ObjectMapper jacksonMapper = new ObjectMapper(); + + @Setup() + public void setup() { + final SimpleModule contiguousListModule = new SimpleModule("contiguous_module"); + contiguousListModule.addSerializer(new ListSerializer()); + jacksonMapper.registerModule(contiguousListModule); + + final RandomStuffGenerator generator = new RandomStuffGenerator(); + for (int i = 0; i < 10_000; i++) { + Customer customer = new Customer(); + String firstName = generator.generateFirstName(); + String lastName = generator.generateLastName(); + customer.name = firstName + " " + lastName; + customer.email = firstName + "." + lastName + "@icemail.com"; + customer.streetname = generator.generateStreetName(); + customer.housenumber = generator.generateSomeNumber(); + customer.city = generator.generateSomeCityInIceland(); + customer.country = generator.generateIceland(); + customers.add(customer); + } + } + } + + @Benchmark + public String contiguous(State state) throws JsonProcessingException { + //naive mimick read from database and add to ContiguousList + ContiguousList customers = new ContiguousList<>(Customer.class); + customers.addAll(state.customers); + + return state.jacksonMapper.writeValueAsString(customers); + } + + @Benchmark + public String classic(State state) throws JsonProcessingException { + //naive mimick read from database and add to ArrayList + List customers = new ArrayList<>(); + customers.addAll(state.customers); + + return state.jacksonMapper.writeValueAsString(customers); + } +} \ No newline at end of file diff --git a/benchmark/src/main/java/com/github/shautvast/contiguous/benchmark/RandomStuffGenerator.java b/benchmark/src/main/java/com/github/shautvast/contiguous/benchmark/RandomStuffGenerator.java new file mode 100644 index 0000000..65afee0 --- /dev/null +++ b/benchmark/src/main/java/com/github/shautvast/contiguous/benchmark/RandomStuffGenerator.java @@ -0,0 +1,55 @@ +package com.github.shautvast.contiguous.benchmark; + +import java.util.List; +import java.util.Random; + +/* Duplicate from demo */ +public class RandomStuffGenerator { + + private final List firstNameParts = List.of("sa", "ka", "zo", "ja", "za", "ka", "po", "ji", "ne", "si", "wi", "ha", "ut", "va", "no", "bo" + , "jo", "fe", "gu"); + + private final List lastNameParts = List.of("fin", "wil", "cat", "loc", "der", "ter", "asp", "pen", "ill", "raf", "gut", "dax", "yin"); + private final List cities = List.of("Reykjavík", "Kópavogur", "Hafnarfjörður", "Akureyri", "Reykjanesbær", "Garðabær", "Mosfellsbær", "Selfoss", "Akranes", "Seltjarnarnes", "Vestmannaeyjar", "Grindavík", "Ísafjörður", "Álftanes", "Sauðárkrókur", "Hveragerði", "Egilsstaðir", "Húsavík", "Borgarnes", "Sandgerði", "Höfn", "Þorlákshöfn", "Garður", "Neskaupstaður", "Dalvík", "Reyðarfjörður", "Siglufjörður", "Vogar", "Stykkishólmur", "Eskifjörður", "Ólafsvík", "Hvolsvöllur", "Bolungarvík", "Hella", "Grundarfjörður", "Blönduós", "Ólafsfjörður", "Fáskrúðsfjörður", "Patreksfjörður", "Seyðisfjörður", "Grundarhverfi", "Hvammstangi", "Stokkseyri", "Eyrarbakki", "Vopnafjörður", "Skagaströnd", "Flúðir", "Vík", "Fellabær", "Hellissandur", "Djúpivogur", "Þórshöfn", "Svalbarðseyri", "Hólmavík", "Grenivík", "Hvanneyri", "Þingeyri", "Búðardalur", "Reykholt", "Hrafnagil", "Suðureyri", "Tálknafjörður", "Bíldudalur", "Mosfellsdalur", "Hnífsdalur", "Reykjahlíð", "Laugarvatn", "Raufarhöfn", "Stöðvarfjörður", "Bifröst", "Flateyri", "Kirkjubæjarklaustur", "Súðavík", "Hrísey", "Hofsós", "Breiðdalsvík", "Rif", "Reykhólar", "Varmahlíð", "Kópasker", "Laugarás", "Borg", "Hauganes", "Hafnir", "Laugar", "Melahverfi", "Tjarnabyggð", "Árskógssandur", "Lónsbakki", "Hólar", "Nesjahverfi", "Sólheimar", "Brúnahlíð", "Drangsnes", "Borgarfjörður eystri", "Árbæjarhverfi", "Brautarholt", "Rauðalækur", "Bakkafjörður", "Innnes", "Grímsey", "Þykkvabær", "Laugarbakki", "Reykholt", "Árnes", "Kristnes", "Kleppjárnsreykir"); + private final Random random = new Random(); + + public String generateFirstName() { + return generateName(firstNameParts); + } + + public String generateLastName() { + return generateName(lastNameParts); + } + + public String generateStreetName() { + StringBuilder name = new StringBuilder(); + int nLastNameParts = random.nextInt(5) + 1; + for (int i = 0; i < nLastNameParts; i++) { + name.append(firstNameParts.get(random.nextInt(firstNameParts.size()))); + name.append(lastNameParts.get(random.nextInt(lastNameParts.size()))); + } + name.append("götu"); + return name.toString(); + } + + public int generateSomeNumber() { + return random.nextInt(1000); + } + + public String generateSomeCityInIceland() { + return cities.get(random.nextInt(cities.size())); + } + + public String generateIceland() { + return "Iceland"; // meant to be humorous + } + + private String generateName(List parts) { + StringBuilder name = new StringBuilder(); + int size = random.nextInt(2) + 2; + for (int i = 0; i < size; i++) { + name.append(parts.get(random.nextInt(parts.size()))); + } + return name.toString(); + } +} diff --git a/demo/pom.xml b/demo/pom.xml index 8fb95a3..9ae91ce 100644 --- a/demo/pom.xml +++ b/demo/pom.xml @@ -4,7 +4,7 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> - nl.sanderhautvast + com.github.shautvast contiguous-pom 1.0-SNAPSHOT @@ -21,12 +21,12 @@ - nl.sanderhautvast + com.github.shautvast contiguous-jdbc 1.0-SNAPSHOT - nl.sanderhautvast + com.github.shautvast contiguous-jackson 1.0-SNAPSHOT @@ -66,7 +66,8 @@ spring-boot-maven-plugin 2.7.12 - nl.sanderhautvast.contiguous.demo.DemoApplication + com.github.shautvast.contiguous.demo.DemoApplication + diff --git a/demo/src/main/java/nl/sanderhautvast/contiguous/demo/DemoApplication.java b/demo/src/main/java/com/github/shautvast/contiguous/demo/DemoApplication.java similarity index 94% rename from demo/src/main/java/nl/sanderhautvast/contiguous/demo/DemoApplication.java rename to demo/src/main/java/com/github/shautvast/contiguous/demo/DemoApplication.java index 6919b2f..cbc205d 100644 --- a/demo/src/main/java/nl/sanderhautvast/contiguous/demo/DemoApplication.java +++ b/demo/src/main/java/com/github/shautvast/contiguous/demo/DemoApplication.java @@ -1,10 +1,10 @@ -package nl.sanderhautvast.contiguous.demo; +package com.github.shautvast.contiguous.demo; import com.fasterxml.jackson.databind.Module; import com.fasterxml.jackson.databind.module.SimpleModule; import lombok.extern.slf4j.Slf4j; -import nl.sanderhautvast.contiguous.ListSerializer; -import nl.sanderhautvast.contiguous.demo.repository.RandomStuffGenerator; +import com.github.shautvast.contiguous.ListSerializer; +import com.github.shautvast.contiguous.demo.repository.RandomStuffGenerator; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.CommandLineRunner; import org.springframework.boot.SpringApplication; diff --git a/demo/src/main/java/nl/sanderhautvast/contiguous/demo/model/Customer.java b/demo/src/main/java/com/github/shautvast/contiguous/demo/model/Customer.java similarity index 85% rename from demo/src/main/java/nl/sanderhautvast/contiguous/demo/model/Customer.java rename to demo/src/main/java/com/github/shautvast/contiguous/demo/model/Customer.java index a67c23c..c632b88 100644 --- a/demo/src/main/java/nl/sanderhautvast/contiguous/demo/model/Customer.java +++ b/demo/src/main/java/com/github/shautvast/contiguous/demo/model/Customer.java @@ -1,4 +1,4 @@ -package nl.sanderhautvast.contiguous.demo.model; +package com.github.shautvast.contiguous.demo.model; import lombok.AllArgsConstructor; import lombok.Builder; diff --git a/demo/src/main/java/nl/sanderhautvast/contiguous/demo/repository/CustomerRepository.java b/demo/src/main/java/com/github/shautvast/contiguous/demo/repository/CustomerRepository.java similarity index 84% rename from demo/src/main/java/nl/sanderhautvast/contiguous/demo/repository/CustomerRepository.java rename to demo/src/main/java/com/github/shautvast/contiguous/demo/repository/CustomerRepository.java index b5bfbda..bf905b2 100644 --- a/demo/src/main/java/nl/sanderhautvast/contiguous/demo/repository/CustomerRepository.java +++ b/demo/src/main/java/com/github/shautvast/contiguous/demo/repository/CustomerRepository.java @@ -1,10 +1,10 @@ -package nl.sanderhautvast.contiguous.demo.repository; +package com.github.shautvast.contiguous.demo.repository; +import com.github.shautvast.contiguous.ContiguousList; +import com.github.shautvast.contiguous.JdbcResults; +import com.github.shautvast.contiguous.demo.model.Customer; import lombok.extern.slf4j.Slf4j; -import nl.sanderhautvast.contiguous.ContiguousList; -import nl.sanderhautvast.contiguous.JdbcResults; -import nl.sanderhautvast.contiguous.demo.model.Customer; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Repository; diff --git a/demo/src/main/java/nl/sanderhautvast/contiguous/demo/repository/RandomStuffGenerator.java b/demo/src/main/java/com/github/shautvast/contiguous/demo/repository/RandomStuffGenerator.java similarity index 98% rename from demo/src/main/java/nl/sanderhautvast/contiguous/demo/repository/RandomStuffGenerator.java rename to demo/src/main/java/com/github/shautvast/contiguous/demo/repository/RandomStuffGenerator.java index b7ad345..8137cf3 100644 --- a/demo/src/main/java/nl/sanderhautvast/contiguous/demo/repository/RandomStuffGenerator.java +++ b/demo/src/main/java/com/github/shautvast/contiguous/demo/repository/RandomStuffGenerator.java @@ -1,4 +1,4 @@ -package nl.sanderhautvast.contiguous.demo.repository; +package com.github.shautvast.contiguous.demo.repository; import java.util.List; import java.util.Random; diff --git a/demo/src/main/java/nl/sanderhautvast/contiguous/demo/rest/DemoRestApi.java b/demo/src/main/java/com/github/shautvast/contiguous/demo/rest/DemoRestApi.java similarity index 71% rename from demo/src/main/java/nl/sanderhautvast/contiguous/demo/rest/DemoRestApi.java rename to demo/src/main/java/com/github/shautvast/contiguous/demo/rest/DemoRestApi.java index c6d83ef..500a8ad 100644 --- a/demo/src/main/java/nl/sanderhautvast/contiguous/demo/rest/DemoRestApi.java +++ b/demo/src/main/java/com/github/shautvast/contiguous/demo/rest/DemoRestApi.java @@ -1,9 +1,9 @@ -package nl.sanderhautvast.contiguous.demo.rest; +package com.github.shautvast.contiguous.demo.rest; +import com.github.shautvast.contiguous.ContiguousList; import lombok.extern.slf4j.Slf4j; -import nl.sanderhautvast.contiguous.ContiguousList; -import nl.sanderhautvast.contiguous.demo.model.Customer; -import nl.sanderhautvast.contiguous.demo.repository.CustomerRepository; +import com.github.shautvast.contiguous.demo.model.Customer; +import com.github.shautvast.contiguous.demo.repository.CustomerRepository; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @@ -23,7 +23,12 @@ public class DemoRestApi { @GetMapping(value = "/api/customers", produces = "application/json") public ContiguousList getCustomers() { - return customerRepository.getAllCustomers(); + try { + return customerRepository.getAllCustomers(); + } catch (Exception e) { + log.error("",e); + throw e; + } } @GetMapping(value = "/api/customers/traditional", produces = "application/json") @@ -35,4 +40,5 @@ public class DemoRestApi { public List getCustomersHybrid() { return customerRepository.getAllCustomersHybrid(); } + } diff --git a/jackson/pom.xml b/jackson/pom.xml index 33eded5..39896ae 100644 --- a/jackson/pom.xml +++ b/jackson/pom.xml @@ -4,7 +4,7 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> - nl.sanderhautvast + com.github.shautvast contiguous-pom 1.0-SNAPSHOT @@ -23,7 +23,7 @@ - nl.sanderhautvast + com.github.shautvast contiguous 1.0-SNAPSHOT diff --git a/jackson/src/main/java/nl/sanderhautvast/contiguous/ListSerializer.java b/jackson/src/main/java/com/github/shautvast/contiguous/ListSerializer.java similarity index 79% rename from jackson/src/main/java/nl/sanderhautvast/contiguous/ListSerializer.java rename to jackson/src/main/java/com/github/shautvast/contiguous/ListSerializer.java index 92b9c8a..f974316 100644 --- a/jackson/src/main/java/nl/sanderhautvast/contiguous/ListSerializer.java +++ b/jackson/src/main/java/com/github/shautvast/contiguous/ListSerializer.java @@ -1,4 +1,4 @@ -package nl.sanderhautvast.contiguous; +package com.github.shautvast.contiguous; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.databind.SerializerProvider; @@ -7,9 +7,9 @@ import com.fasterxml.jackson.databind.ser.std.StdSerializer; import java.io.IOException; import java.util.Iterator; -public class ListSerializer extends StdSerializer> { +public class ListSerializer extends StdSerializer> { - @SuppressWarnings("unchecked") + @SuppressWarnings({"unchecked", "rawtypes"}) public ListSerializer() { super((Class) ContiguousList.class); // ? } @@ -26,6 +26,7 @@ public class ListSerializer extends StdSerializer> { } generator.writeEndArray(); + clist.close(); } } diff --git a/jackson/src/test/java/nl/sanderhautvast/contiguous/AdamsObject.java b/jackson/src/test/java/com/github/shautvast/contiguous/AdamsObject.java similarity index 87% rename from jackson/src/test/java/nl/sanderhautvast/contiguous/AdamsObject.java rename to jackson/src/test/java/com/github/shautvast/contiguous/AdamsObject.java index 48421aa..428a7c6 100644 --- a/jackson/src/test/java/nl/sanderhautvast/contiguous/AdamsObject.java +++ b/jackson/src/test/java/com/github/shautvast/contiguous/AdamsObject.java @@ -1,4 +1,4 @@ -package nl.sanderhautvast.contiguous; +package com.github.shautvast.contiguous; public class AdamsObject { private String name; diff --git a/jackson/src/test/java/nl/sanderhautvast/contiguous/ListSerializerTest.java b/jackson/src/test/java/com/github/shautvast/contiguous/ListSerializerTest.java similarity index 95% rename from jackson/src/test/java/nl/sanderhautvast/contiguous/ListSerializerTest.java rename to jackson/src/test/java/com/github/shautvast/contiguous/ListSerializerTest.java index fd15b5d..eae29ca 100644 --- a/jackson/src/test/java/nl/sanderhautvast/contiguous/ListSerializerTest.java +++ b/jackson/src/test/java/com/github/shautvast/contiguous/ListSerializerTest.java @@ -1,4 +1,4 @@ -package nl.sanderhautvast.contiguous; +package com.github.shautvast.contiguous; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; @@ -17,7 +17,7 @@ class ListSerializerTest { public void setup(){ mapper = new ObjectMapper(); final SimpleModule module = new SimpleModule("mySerializers"); - module.addSerializer(new ListSerializer<>()); + module.addSerializer(new ListSerializer()); mapper.registerModule(module); } @Test diff --git a/jdbc/pom.xml b/jdbc/pom.xml index 0244b46..fa6b8c8 100644 --- a/jdbc/pom.xml +++ b/jdbc/pom.xml @@ -4,7 +4,7 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> - nl.sanderhautvast + com.github.shautvast contiguous-pom 1.0-SNAPSHOT @@ -23,7 +23,7 @@ - nl.sanderhautvast + com.github.shautvast contiguous 1.0-SNAPSHOT diff --git a/jdbc/src/main/java/nl/sanderhautvast/contiguous/JdbcResults.java b/jdbc/src/main/java/com/github/shautvast/contiguous/JdbcResults.java similarity index 98% rename from jdbc/src/main/java/nl/sanderhautvast/contiguous/JdbcResults.java rename to jdbc/src/main/java/com/github/shautvast/contiguous/JdbcResults.java index 7f8dad7..e05b69e 100644 --- a/jdbc/src/main/java/nl/sanderhautvast/contiguous/JdbcResults.java +++ b/jdbc/src/main/java/com/github/shautvast/contiguous/JdbcResults.java @@ -1,4 +1,4 @@ -package nl.sanderhautvast.contiguous; +package com.github.shautvast.contiguous; import java.sql.ResultSet; import java.sql.SQLException; diff --git a/jdbc/src/test/java/nl/sanderhautvast/contiguous/JdbcResultsTest.java b/jdbc/src/test/java/com/github/shautvast/contiguous/JdbcResultsTest.java similarity index 96% rename from jdbc/src/test/java/nl/sanderhautvast/contiguous/JdbcResultsTest.java rename to jdbc/src/test/java/com/github/shautvast/contiguous/JdbcResultsTest.java index 396813f..a6a99ff 100644 --- a/jdbc/src/test/java/nl/sanderhautvast/contiguous/JdbcResultsTest.java +++ b/jdbc/src/test/java/com/github/shautvast/contiguous/JdbcResultsTest.java @@ -1,6 +1,5 @@ -package nl.sanderhautvast.contiguous; +package com.github.shautvast.contiguous; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; diff --git a/jdbc/src/test/java/nl/sanderhautvast/contiguous/President.java b/jdbc/src/test/java/com/github/shautvast/contiguous/President.java similarity index 83% rename from jdbc/src/test/java/nl/sanderhautvast/contiguous/President.java rename to jdbc/src/test/java/com/github/shautvast/contiguous/President.java index 8bd8484..f133c0a 100644 --- a/jdbc/src/test/java/nl/sanderhautvast/contiguous/President.java +++ b/jdbc/src/test/java/com/github/shautvast/contiguous/President.java @@ -1,4 +1,4 @@ -package nl.sanderhautvast.contiguous; +package com.github.shautvast.contiguous; import lombok.AllArgsConstructor; import lombok.Data; diff --git a/jdbc/src/test/java/nl/sanderhautvast/contiguous/Scientist.java b/jdbc/src/test/java/com/github/shautvast/contiguous/Scientist.java similarity index 84% rename from jdbc/src/test/java/nl/sanderhautvast/contiguous/Scientist.java rename to jdbc/src/test/java/com/github/shautvast/contiguous/Scientist.java index 6626f8e..6d1b54e 100644 --- a/jdbc/src/test/java/nl/sanderhautvast/contiguous/Scientist.java +++ b/jdbc/src/test/java/com/github/shautvast/contiguous/Scientist.java @@ -1,4 +1,4 @@ -package nl.sanderhautvast.contiguous; +package com.github.shautvast.contiguous; import lombok.AllArgsConstructor; import lombok.Data; diff --git a/jmeter-test.jmx b/jmeter-test.jmx index b799a2d..fde81ca 100644 --- a/jmeter-test.jmx +++ b/jmeter-test.jmx @@ -16,17 +16,17 @@ continue false - 100 + 1000 - 1 - 1 + 3 + 10 false true - + @@ -34,7 +34,7 @@ 8080 http - /api/customers + /api/customers/streamon GET true false @@ -45,7 +45,7 @@ - + @@ -83,6 +83,49 @@ + + + + + localhost + 8080 + http + + api/customers/toy + GET + true + false + true + false + + + + + + + 0 + 100.0 + + + + + + + localhost + 8080 + http + + /api/customers/streamon2 + GET + true + false + true + false + + + + + false diff --git a/lib/pom.xml b/lib/pom.xml index 1fc0c7c..bd86205 100644 --- a/lib/pom.xml +++ b/lib/pom.xml @@ -5,7 +5,7 @@ 4.0.0 - nl.sanderhautvast + com.github.shautvast contiguous-pom 1.0-SNAPSHOT @@ -16,8 +16,8 @@ jar - 9 - 9 + 21 + 21 UTF-8 diff --git a/lib/src/main/java/nl/sanderhautvast/contiguous/BigDecimalHandler.java b/lib/src/main/java/com/github/shautvast/contiguous/BigDecimalHandler.java similarity index 92% rename from lib/src/main/java/nl/sanderhautvast/contiguous/BigDecimalHandler.java rename to lib/src/main/java/com/github/shautvast/contiguous/BigDecimalHandler.java index ecbebd1..3c80ecb 100644 --- a/lib/src/main/java/nl/sanderhautvast/contiguous/BigDecimalHandler.java +++ b/lib/src/main/java/com/github/shautvast/contiguous/BigDecimalHandler.java @@ -1,4 +1,4 @@ -package nl.sanderhautvast.contiguous; +package com.github.shautvast.contiguous; import java.lang.invoke.MethodHandle; import java.math.BigDecimal; diff --git a/lib/src/main/java/nl/sanderhautvast/contiguous/BigIntegerHandler.java b/lib/src/main/java/com/github/shautvast/contiguous/BigIntegerHandler.java similarity index 92% rename from lib/src/main/java/nl/sanderhautvast/contiguous/BigIntegerHandler.java rename to lib/src/main/java/com/github/shautvast/contiguous/BigIntegerHandler.java index ba70f41..7da9133 100644 --- a/lib/src/main/java/nl/sanderhautvast/contiguous/BigIntegerHandler.java +++ b/lib/src/main/java/com/github/shautvast/contiguous/BigIntegerHandler.java @@ -1,4 +1,4 @@ -package nl.sanderhautvast.contiguous; +package com.github.shautvast.contiguous; import java.lang.invoke.MethodHandle; import java.math.BigInteger; diff --git a/lib/src/main/java/com/github/shautvast/contiguous/BufferCache.java b/lib/src/main/java/com/github/shautvast/contiguous/BufferCache.java new file mode 100644 index 0000000..b0f4ccb --- /dev/null +++ b/lib/src/main/java/com/github/shautvast/contiguous/BufferCache.java @@ -0,0 +1,24 @@ +package com.github.shautvast.contiguous; + +import java.lang.ref.SoftReference; +import java.nio.ByteBuffer; +import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentLinkedQueue; + +/** + * Boundless cache something + */ +class BufferCache { + private static final ConcurrentHashMap cache = new ConcurrentHashMap<>(); + + static ByteBuffer get(int size) { + ByteBuffer byteBuffer = Optional.ofNullable(cache.get(size)).orElseGet(() -> ByteBuffer.allocate(size)); + byteBuffer.position(0); + return byteBuffer; + } + + static void release(ByteBuffer byteBuffer) { + cache.put(byteBuffer.capacity(), byteBuffer); + } +} diff --git a/lib/src/main/java/nl/sanderhautvast/contiguous/BuiltinTypeHandler.java b/lib/src/main/java/com/github/shautvast/contiguous/BuiltinTypeHandler.java similarity index 96% rename from lib/src/main/java/nl/sanderhautvast/contiguous/BuiltinTypeHandler.java rename to lib/src/main/java/com/github/shautvast/contiguous/BuiltinTypeHandler.java index bf8e74a..35446e9 100644 --- a/lib/src/main/java/nl/sanderhautvast/contiguous/BuiltinTypeHandler.java +++ b/lib/src/main/java/com/github/shautvast/contiguous/BuiltinTypeHandler.java @@ -1,4 +1,4 @@ -package nl.sanderhautvast.contiguous; +package com.github.shautvast.contiguous; import java.lang.invoke.MethodHandle; @@ -11,7 +11,7 @@ import java.lang.invoke.MethodHandle; * of the bean that it needs to call 'runtime' (after instantiation of the list), * ie. when a bean is added or retrieved from the list */ -public abstract class BuiltinTypeHandler extends TypeHandler { +abstract class BuiltinTypeHandler extends TypeHandler { public BuiltinTypeHandler(Class type, String name, MethodHandle getter, MethodHandle setter) { super(type, name, getter, setter); } diff --git a/lib/src/main/java/nl/sanderhautvast/contiguous/ByteHandler.java b/lib/src/main/java/com/github/shautvast/contiguous/ByteHandler.java similarity index 94% rename from lib/src/main/java/nl/sanderhautvast/contiguous/ByteHandler.java rename to lib/src/main/java/com/github/shautvast/contiguous/ByteHandler.java index 1b0cb3d..badd6fa 100644 --- a/lib/src/main/java/nl/sanderhautvast/contiguous/ByteHandler.java +++ b/lib/src/main/java/com/github/shautvast/contiguous/ByteHandler.java @@ -1,4 +1,4 @@ -package nl.sanderhautvast.contiguous; +package com.github.shautvast.contiguous; import java.lang.invoke.MethodHandle; diff --git a/lib/src/main/java/nl/sanderhautvast/contiguous/CompoundTypeHandler.java b/lib/src/main/java/com/github/shautvast/contiguous/CompoundTypeHandler.java similarity index 94% rename from lib/src/main/java/nl/sanderhautvast/contiguous/CompoundTypeHandler.java rename to lib/src/main/java/com/github/shautvast/contiguous/CompoundTypeHandler.java index de71cd7..1996d1f 100644 --- a/lib/src/main/java/nl/sanderhautvast/contiguous/CompoundTypeHandler.java +++ b/lib/src/main/java/com/github/shautvast/contiguous/CompoundTypeHandler.java @@ -1,4 +1,4 @@ -package nl.sanderhautvast.contiguous; +package com.github.shautvast.contiguous; import java.lang.reflect.Field; import java.util.*; diff --git a/lib/src/main/java/nl/sanderhautvast/contiguous/ContiguousList.java b/lib/src/main/java/com/github/shautvast/contiguous/ContiguousList.java similarity index 90% rename from lib/src/main/java/nl/sanderhautvast/contiguous/ContiguousList.java rename to lib/src/main/java/com/github/shautvast/contiguous/ContiguousList.java index 25fce45..c6b8256 100644 --- a/lib/src/main/java/nl/sanderhautvast/contiguous/ContiguousList.java +++ b/lib/src/main/java/com/github/shautvast/contiguous/ContiguousList.java @@ -1,4 +1,4 @@ -package nl.sanderhautvast.contiguous; +package com.github.shautvast.contiguous; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; @@ -56,22 +56,27 @@ public class ContiguousList extends NotImplementedList implements List /* * storage for dehydated objects */ - private ByteBuffer data = ByteBuffer.allocate(4096);//TODO create constructor with capacity + private ByteBuffer data = BufferCache.get(4096); private int bufferPosition; - private ArrayList elementIndices = new ArrayList<>(); // avoids autoboxing. Could also use standard ArrayList though + private final ArrayList elementIndices = new ArrayList<>(); // avoids autoboxing. Could also use standard ArrayList though // is there a standard lib IntList?? private int size; - private TypeHandler rootHandler; + private final TypeHandler rootHandler; + private static final Map, TypeHandler> TYPE_HANDLERS = new HashMap<>(); public ContiguousList(Class type) { - inspectType(type); + this.rootHandler = inspectType(type); elementIndices.add(0); // index of first element } + public void close(){ + BufferCache.release(this.data); + } + /* * Get a list of setters and getters to execute later on to get/set the values of the object * @@ -80,25 +85,22 @@ public class ContiguousList extends NotImplementedList implements List * The advantage of the current implementation is that the binary data is not aware of the actual * object graph. It only knows the 'primitive' values. */ - private void inspectType(Class elementClass) { - if (PropertyHandlerFactory.isBuiltInType(elementClass)) { - this.rootHandler = PropertyHandlerFactory.forType(elementClass); - } else { - CompoundTypeHandler compoundType = new CompoundTypeHandler(elementClass); - this.rootHandler = compoundType; - try { - addPropertyHandlersForCompoundType(elementClass, compoundType); - } catch (IllegalAccessException e) { - throw new IllegalStateException(e); - } - } + private TypeHandler inspectType(Class elementClass) { + return TYPE_HANDLERS.computeIfAbsent(elementClass, k -> + PropertyHandlerFactory.forType(elementClass) + .orElseGet(() -> { + TypeHandler compoundTypeHandler = new CompoundTypeHandler(elementClass); + addPropertyHandlersForCompoundType(elementClass, (CompoundTypeHandler) compoundTypeHandler); + return compoundTypeHandler; + }) + ); } /* * using reflection find all properties in the element, recursing down when the property is compound */ - private void addPropertyHandlersForCompoundType(Class type, CompoundTypeHandler parentCompoundType) throws IllegalAccessException { - final MethodHandles.Lookup lookup = MethodHandles.privateLookupIn(type, MethodHandles.lookup()); + private void addPropertyHandlersForCompoundType(Class type, CompoundTypeHandler parentCompoundType) { + final MethodHandles.Lookup lookup = getLookup(type); Arrays.stream(type.getDeclaredFields()) .forEach(field -> { try { @@ -106,18 +108,16 @@ public class ContiguousList extends NotImplementedList implements List MethodHandle getter = lookup.findGetter(type, field.getName(), fieldType); MethodHandle setter = lookup.findSetter(type, field.getName(), fieldType); - if (PropertyHandlerFactory.isBuiltInType(fieldType)) { - BuiltinTypeHandler primitiveType = - PropertyHandlerFactory.forType(fieldType, field.getName(), getter, setter); - - parentCompoundType.addHandler(field.getName(), primitiveType); + Optional typeHandler = PropertyHandlerFactory.forType(fieldType, field.getName(), getter, setter); + if (typeHandler.isPresent()) { + parentCompoundType.addHandler(field.getName(), (BuiltinTypeHandler) typeHandler.get()); } else { - CompoundTypeHandler newParent = new CompoundTypeHandler(fieldType, field.getName()); - newParent.setGetter(getter); - newParent.setSetter(setter); - parentCompoundType.addChild(field, newParent); + CompoundTypeHandler handler = new CompoundTypeHandler(fieldType, field.getName()); + handler.setGetter(getter); + handler.setSetter(setter); + parentCompoundType.addChild(field, handler); - addPropertyHandlersForCompoundType(fieldType, newParent); + addPropertyHandlersForCompoundType(fieldType, handler); } } catch (Exception e) { throw new RuntimeException(e); @@ -125,6 +125,14 @@ public class ContiguousList extends NotImplementedList implements List }); } + private static MethodHandles.Lookup getLookup(Class type) { + try { + return MethodHandles.privateLookupIn(type, MethodHandles.lookup()); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + } + @Override @SuppressWarnings("Contract") public boolean add(E element) { @@ -270,7 +278,6 @@ public class ContiguousList extends NotImplementedList implements List } data.position(elementIndices.get(index)); if (rootHandler instanceof BuiltinTypeHandler) { - BuiltinTypeHandler handler = (BuiltinTypeHandler) rootHandler; return getValue(handler); } @@ -280,16 +287,14 @@ public class ContiguousList extends NotImplementedList implements List copyDataIntoStringBuilder(s, (CompoundTypeHandler) rootHandler); s.append("}"); return s.toString(); - } private String getValue(BuiltinTypeHandler handler) { - Object read = ValueReader.read(data); - String out = handler.cast(read).toString(); + String value = String.valueOf(ValueReader.read(data)); if (handler instanceof StringHandler) { - out = quote(out); + return quote(value); } - return out; + return value; } private static String quote(String out) { @@ -305,8 +310,9 @@ public class ContiguousList extends NotImplementedList implements List compoundType.getProperties().forEach(property -> { if (property instanceof BuiltinTypeHandler) { BuiltinTypeHandler typeHandler = (BuiltinTypeHandler) property; - s.append(quote(typeHandler.getName())) - .append(": ") + s.append("\"") + .append(typeHandler.getName()) + .append("\": ") .append(getValue(typeHandler)); } else { CompoundTypeHandler p = (CompoundTypeHandler) property; @@ -608,8 +614,9 @@ public class ContiguousList extends NotImplementedList implements List private void ensureFree(int length) { while (bufferPosition + length > data.capacity()) { - byte[] bytes = this.data.array(); - this.data = ByteBuffer.allocate(this.data.capacity() * 2); + ByteBuffer bytes = this.data; + BufferCache.release(this.data); + this.data = BufferCache.get((int)(bytes.capacity() * 1.5)); this.data.put(bytes); } } diff --git a/lib/src/main/java/nl/sanderhautvast/contiguous/DoubleHandler.java b/lib/src/main/java/com/github/shautvast/contiguous/DoubleHandler.java similarity index 90% rename from lib/src/main/java/nl/sanderhautvast/contiguous/DoubleHandler.java rename to lib/src/main/java/com/github/shautvast/contiguous/DoubleHandler.java index 4c26d23..fe7c814 100644 --- a/lib/src/main/java/nl/sanderhautvast/contiguous/DoubleHandler.java +++ b/lib/src/main/java/com/github/shautvast/contiguous/DoubleHandler.java @@ -1,4 +1,4 @@ -package nl.sanderhautvast.contiguous; +package com.github.shautvast.contiguous; import java.lang.invoke.MethodHandle; diff --git a/lib/src/main/java/nl/sanderhautvast/contiguous/FloatHandler.java b/lib/src/main/java/com/github/shautvast/contiguous/FloatHandler.java similarity index 89% rename from lib/src/main/java/nl/sanderhautvast/contiguous/FloatHandler.java rename to lib/src/main/java/com/github/shautvast/contiguous/FloatHandler.java index 69067ee..c0d0ba5 100644 --- a/lib/src/main/java/nl/sanderhautvast/contiguous/FloatHandler.java +++ b/lib/src/main/java/com/github/shautvast/contiguous/FloatHandler.java @@ -1,4 +1,4 @@ -package nl.sanderhautvast.contiguous; +package com.github.shautvast.contiguous; import java.lang.invoke.MethodHandle; diff --git a/lib/src/main/java/nl/sanderhautvast/contiguous/IntegerHandler.java b/lib/src/main/java/com/github/shautvast/contiguous/IntegerHandler.java similarity index 95% rename from lib/src/main/java/nl/sanderhautvast/contiguous/IntegerHandler.java rename to lib/src/main/java/com/github/shautvast/contiguous/IntegerHandler.java index 014e47d..308001c 100644 --- a/lib/src/main/java/nl/sanderhautvast/contiguous/IntegerHandler.java +++ b/lib/src/main/java/com/github/shautvast/contiguous/IntegerHandler.java @@ -1,4 +1,4 @@ -package nl.sanderhautvast.contiguous; +package com.github.shautvast.contiguous; import java.lang.invoke.MethodHandle; diff --git a/lib/src/main/java/nl/sanderhautvast/contiguous/LongHandler.java b/lib/src/main/java/com/github/shautvast/contiguous/LongHandler.java similarity index 89% rename from lib/src/main/java/nl/sanderhautvast/contiguous/LongHandler.java rename to lib/src/main/java/com/github/shautvast/contiguous/LongHandler.java index 81b5556..7cb1981 100644 --- a/lib/src/main/java/nl/sanderhautvast/contiguous/LongHandler.java +++ b/lib/src/main/java/com/github/shautvast/contiguous/LongHandler.java @@ -1,4 +1,4 @@ -package nl.sanderhautvast.contiguous; +package com.github.shautvast.contiguous; import java.lang.invoke.MethodHandle; diff --git a/lib/src/main/java/nl/sanderhautvast/contiguous/NotImplementedList.java b/lib/src/main/java/com/github/shautvast/contiguous/NotImplementedList.java similarity index 98% rename from lib/src/main/java/nl/sanderhautvast/contiguous/NotImplementedList.java rename to lib/src/main/java/com/github/shautvast/contiguous/NotImplementedList.java index 051c708..8214924 100644 --- a/lib/src/main/java/nl/sanderhautvast/contiguous/NotImplementedList.java +++ b/lib/src/main/java/com/github/shautvast/contiguous/NotImplementedList.java @@ -1,4 +1,4 @@ -package nl.sanderhautvast.contiguous; +package com.github.shautvast.contiguous; import java.util.*; import java.util.function.UnaryOperator; diff --git a/lib/src/main/java/nl/sanderhautvast/contiguous/PropertyHandlerFactory.java b/lib/src/main/java/com/github/shautvast/contiguous/PropertyHandlerFactory.java similarity index 60% rename from lib/src/main/java/nl/sanderhautvast/contiguous/PropertyHandlerFactory.java rename to lib/src/main/java/com/github/shautvast/contiguous/PropertyHandlerFactory.java index d8cf82b..0ef95b6 100644 --- a/lib/src/main/java/nl/sanderhautvast/contiguous/PropertyHandlerFactory.java +++ b/lib/src/main/java/com/github/shautvast/contiguous/PropertyHandlerFactory.java @@ -1,17 +1,16 @@ -package nl.sanderhautvast.contiguous; +package com.github.shautvast.contiguous; import java.lang.invoke.MethodHandle; import java.lang.reflect.InvocationTargetException; import java.math.BigDecimal; import java.math.BigInteger; -import java.util.HashMap; -import java.util.Map; +import java.util.*; /* * Maps the propertyvalue type to a PropertyHandler */ final class PropertyHandlerFactory { - private static final Map, Class>> TYPE_HANDLERS = new HashMap<>(); + private static final Map, Class>> BUILTIN = new HashMap<>(); private PropertyHandlerFactory() { } @@ -35,27 +34,23 @@ final class PropertyHandlerFactory { register(BigDecimal.class, BigDecimalHandler.class); //Date/Timestamp //LocalDate/time + } - public static boolean isBuiltInType(Class type) { - return TYPE_HANDLERS.containsKey(type); - } - - public static BuiltinTypeHandler forType(Class type, String name, MethodHandle getter, MethodHandle setter) { - try { - Class> appenderClass = TYPE_HANDLERS.get(type); - if (appenderClass == null) { - throw new IllegalStateException("No Handler for " + type.getName()); + @SuppressWarnings("unchecked") + public static Optional forType(Class type, String name, MethodHandle getter, MethodHandle setter) { + return Optional.ofNullable(BUILTIN.get(type)).map(appenderClass -> { + try { + return (BuiltinTypeHandler) appenderClass.getDeclaredConstructor(String.class, MethodHandle.class, MethodHandle.class) + .newInstance(name, getter, setter); + } catch (NoSuchMethodException | InstantiationException | IllegalAccessException | + InvocationTargetException e) { + throw new IllegalStateException(e); } - return (BuiltinTypeHandler) appenderClass.getDeclaredConstructor(String.class, MethodHandle.class, MethodHandle.class) - .newInstance(name, getter, setter); - } catch (NoSuchMethodException | InstantiationException | IllegalAccessException | - InvocationTargetException e) { - throw new IllegalStateException(e); - } + }); } - public static BuiltinTypeHandler forType(Class type) { + public static Optional forType(Class type) { return forType(type, null, null, null); } @@ -63,6 +58,6 @@ final class PropertyHandlerFactory { * register a new TypeHandler that cannot be derived from bean properties */ public static void register(Class type, Class> typehandler) { - TYPE_HANDLERS.put(type, typehandler); + BUILTIN.put(type, typehandler); } } diff --git a/lib/src/main/java/nl/sanderhautvast/contiguous/ShortHandler.java b/lib/src/main/java/com/github/shautvast/contiguous/ShortHandler.java similarity index 94% rename from lib/src/main/java/nl/sanderhautvast/contiguous/ShortHandler.java rename to lib/src/main/java/com/github/shautvast/contiguous/ShortHandler.java index c58dc1e..c752c7f 100644 --- a/lib/src/main/java/nl/sanderhautvast/contiguous/ShortHandler.java +++ b/lib/src/main/java/com/github/shautvast/contiguous/ShortHandler.java @@ -1,4 +1,4 @@ -package nl.sanderhautvast.contiguous; +package com.github.shautvast.contiguous; import java.lang.invoke.MethodHandle; diff --git a/lib/src/main/java/nl/sanderhautvast/contiguous/StringHandler.java b/lib/src/main/java/com/github/shautvast/contiguous/StringHandler.java similarity index 90% rename from lib/src/main/java/nl/sanderhautvast/contiguous/StringHandler.java rename to lib/src/main/java/com/github/shautvast/contiguous/StringHandler.java index 0a83ded..aed7d8e 100644 --- a/lib/src/main/java/nl/sanderhautvast/contiguous/StringHandler.java +++ b/lib/src/main/java/com/github/shautvast/contiguous/StringHandler.java @@ -1,4 +1,4 @@ -package nl.sanderhautvast.contiguous; +package com.github.shautvast.contiguous; import java.lang.invoke.MethodHandle; diff --git a/lib/src/main/java/nl/sanderhautvast/contiguous/TypeHandler.java b/lib/src/main/java/com/github/shautvast/contiguous/TypeHandler.java similarity index 91% rename from lib/src/main/java/nl/sanderhautvast/contiguous/TypeHandler.java rename to lib/src/main/java/com/github/shautvast/contiguous/TypeHandler.java index 5f4eeee..de1193b 100644 --- a/lib/src/main/java/nl/sanderhautvast/contiguous/TypeHandler.java +++ b/lib/src/main/java/com/github/shautvast/contiguous/TypeHandler.java @@ -1,9 +1,9 @@ -package nl.sanderhautvast.contiguous; +package com.github.shautvast.contiguous; import java.lang.invoke.MethodHandle; /** - * Abstract basertype over handlers for 'primitives' (ie. long, but also Long, + * Abstract basetype over handlers for 'primitives' (ie. long, but also Long, * String..=> built-in types) and compound types (your own). * Common ancestor primarily to iterator over properties of any type. * The respective functions are completely different though, and we need `instanceof` to check for the diff --git a/lib/src/main/java/nl/sanderhautvast/contiguous/ValueReader.java b/lib/src/main/java/com/github/shautvast/contiguous/ValueReader.java similarity index 97% rename from lib/src/main/java/nl/sanderhautvast/contiguous/ValueReader.java rename to lib/src/main/java/com/github/shautvast/contiguous/ValueReader.java index e9e3862..9810756 100644 --- a/lib/src/main/java/nl/sanderhautvast/contiguous/ValueReader.java +++ b/lib/src/main/java/com/github/shautvast/contiguous/ValueReader.java @@ -1,4 +1,4 @@ -package nl.sanderhautvast.contiguous; +package com.github.shautvast.contiguous; import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; @@ -8,7 +8,7 @@ import java.nio.charset.StandardCharsets; * the layout is SQLite-like type:Varint, value byte[] * Varint: byte[] */ -class ValueReader { +public class ValueReader { /** * Reads a value from the buffer. diff --git a/lib/src/main/java/nl/sanderhautvast/contiguous/Varint.java b/lib/src/main/java/com/github/shautvast/contiguous/Varint.java similarity index 98% rename from lib/src/main/java/nl/sanderhautvast/contiguous/Varint.java rename to lib/src/main/java/com/github/shautvast/contiguous/Varint.java index 5626cdc..31d0226 100644 --- a/lib/src/main/java/nl/sanderhautvast/contiguous/Varint.java +++ b/lib/src/main/java/com/github/shautvast/contiguous/Varint.java @@ -1,4 +1,4 @@ -package nl.sanderhautvast.contiguous; +package com.github.shautvast.contiguous; import java.nio.ByteBuffer; @@ -6,7 +6,7 @@ import java.nio.ByteBuffer; * Writes integers to byte representation like Sqlite's putVarint64 * not threadsafe (take out B8 and B9 if you need that) */ -final class Varint { +public final class Varint { private Varint() { } diff --git a/lib/src/main/java/com/github/shautvast/contiguous/asm/AsmContiguousList.java b/lib/src/main/java/com/github/shautvast/contiguous/asm/AsmContiguousList.java new file mode 100644 index 0000000..3ff0e5f --- /dev/null +++ b/lib/src/main/java/com/github/shautvast/contiguous/asm/AsmContiguousList.java @@ -0,0 +1,147 @@ +package com.github.shautvast.contiguous.asm; + +import com.github.shautvast.contiguous.ValueReader; +import com.github.shautvast.contiguous.Varint; + +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; + +public class AsmContiguousList { + + private static final byte[] DOUBLE_TYPE = {7}; + private static final byte[] FLOAT_TYPE = {10}; // not in line with SQLite anymore + private static final int STRING_OFFSET = 13; + private static final int BYTES_OFFSET = 12; // blob TODO decide if include + public static final int MAX_24BITS = 8388607; + public static final long MAX_48BITS = 140737488355327L; + + /* + * storage for dehydrated objects + */ + private ByteBuffer data = ByteBuffer.allocate(4096);//TODO create constructor with capacity + + private int bufferPosition; + + private final ArrayList elementIndices = new ArrayList<>(); + + private int size; + + private final AsmTypeHandler rootHandler; +// private static final Map, TypeHandler> TYPE_HANDLERS = new HashMap<>(); + + public AsmContiguousList(Class elementType) { + this.rootHandler = new StringHandler(); + elementIndices.add(0); // index of first element + bufferPosition = 0; + } + + public boolean add(E element) { + if (element == null) { + return false; + } + storePropertyData(element, rootHandler); + extend(); + return true; + } + + @SuppressWarnings("unchecked") + public E get(int index) { + checkbounds(index); + data.position(elementIndices.get(index)); + Object read = ValueReader.read(data); + return (E) rootHandler.cast(read); + // create a new instance of the list element type + } + + public String getAsJson(int index) { + checkbounds(index); + data.position(elementIndices.get(index)); + if (rootHandler instanceof BuiltinHandler) { + return getValue(rootHandler); + } + return null; + } + + private void checkbounds(int index) { + if (index < 0 || index >= size) { + throw new IndexOutOfBoundsException("index <0 or >" + size); + } + } + + private String getValue(AsmTypeHandler handler) { + String value = String.valueOf(ValueReader.read(data)); + if (handler instanceof BuiltinHandler) { + return quote(value); + } + return value; + } + + public int size() { + return size; + } + + public boolean isEmpty() { + return size == 0; + } + + private void storePropertyData(Object element, AsmTypeHandler typeHandler) { + if (typeHandler instanceof BuiltinHandler) { + typeHandler.storePropertyValue(element); + } + } + + private String quote(String out) { + out = "\"" + out + "\""; + return out; + } + + private void store(byte[] bytes) { + ensureFree(bytes.length); + data.position(bufferPosition); // ensures intermittent reads/writes are safe + data.put(bytes); + bufferPosition += bytes.length; + } + + private void store0() { + ensureFree(1); + data.put((byte) 0); + bufferPosition += 1; + } + + void storeString(String value) { + if (value == null) { + store0(); + } else { + byte[] utf = value.getBytes(StandardCharsets.UTF_8); + store(Varint.write(((long) (utf.length) << 1) + STRING_OFFSET)); + store(utf); + } + } + + private void ensureFree(int length) { + while (bufferPosition + length > data.capacity()) { + ByteBuffer bytes = this.data; + this.data = ByteBuffer.allocate(this.data.capacity() * 2); + this.data.put(bytes); + } + } + + void extend() { + size += 1; + // keep track of index of element in data + elementIndices.add(bufferPosition); + } + + class StringHandler extends BuiltinHandler { + @Override + protected String getValue(Object instance) { + return instance.toString(); + } + + public void store(String value){ + storeString(value); + } + } +} + diff --git a/lib/src/main/java/com/github/shautvast/contiguous/asm/AsmTypeHandler.java b/lib/src/main/java/com/github/shautvast/contiguous/asm/AsmTypeHandler.java new file mode 100644 index 0000000..c587a19 --- /dev/null +++ b/lib/src/main/java/com/github/shautvast/contiguous/asm/AsmTypeHandler.java @@ -0,0 +1,16 @@ +package com.github.shautvast.contiguous.asm; + +public abstract class AsmTypeHandler { + public Object cast(Object value) { + return value; + } + + void storePropertyValue(Object instance) { + T propertyValue = getValue(instance); + store(propertyValue); + } + + protected abstract T getValue(Object instance); + + public abstract void store(T value); +} diff --git a/lib/src/main/java/com/github/shautvast/contiguous/asm/BuiltinHandler.java b/lib/src/main/java/com/github/shautvast/contiguous/asm/BuiltinHandler.java new file mode 100644 index 0000000..b7438a8 --- /dev/null +++ b/lib/src/main/java/com/github/shautvast/contiguous/asm/BuiltinHandler.java @@ -0,0 +1,4 @@ +package com.github.shautvast.contiguous.asm; + +public abstract class BuiltinHandler extends AsmTypeHandler { +} diff --git a/lib/src/test/java/nl/sanderhautvast/contiguous/ByteBean.java b/lib/src/test/java/com/github/shautvast/contiguous/ByteBean.java similarity index 80% rename from lib/src/test/java/nl/sanderhautvast/contiguous/ByteBean.java rename to lib/src/test/java/com/github/shautvast/contiguous/ByteBean.java index 093a911..9bb8de9 100644 --- a/lib/src/test/java/nl/sanderhautvast/contiguous/ByteBean.java +++ b/lib/src/test/java/com/github/shautvast/contiguous/ByteBean.java @@ -1,4 +1,4 @@ -package nl.sanderhautvast.contiguous; +package com.github.shautvast.contiguous; import lombok.AllArgsConstructor; import lombok.Data; diff --git a/lib/src/test/java/nl/sanderhautvast/contiguous/ContiguousListTest.java b/lib/src/test/java/com/github/shautvast/contiguous/ContiguousListTest.java similarity index 93% rename from lib/src/test/java/nl/sanderhautvast/contiguous/ContiguousListTest.java rename to lib/src/test/java/com/github/shautvast/contiguous/ContiguousListTest.java index 9878592..20e09f2 100644 --- a/lib/src/test/java/nl/sanderhautvast/contiguous/ContiguousListTest.java +++ b/lib/src/test/java/com/github/shautvast/contiguous/ContiguousListTest.java @@ -1,4 +1,4 @@ -package nl.sanderhautvast.contiguous; +package com.github.shautvast.contiguous; import org.junit.jupiter.api.Test; @@ -74,7 +74,6 @@ public class ContiguousListTest { assertArrayEquals(new byte[]{1, 42}, beanList.getData()); - assertArrayEquals(new int[]{0, 2}, beanList.getElementIndices()); } @Test @@ -84,7 +83,6 @@ public class ContiguousListTest { assertArrayEquals(new byte[]{1, -42}, beanList.getData()); - assertArrayEquals(new int[]{0, 2}, beanList.getElementIndices()); } @Test @@ -206,7 +204,7 @@ public class ContiguousListTest { @Test - public void testSetterIterator() { + void testSetterIterator() { ContiguousList integers = new ContiguousList<>(NestedBean.class); ContiguousList.SetterIterator iterator = integers.setterIterator(); @@ -222,4 +220,17 @@ public class ContiguousListTest { assertEquals("Magrathea", nestedBean.getStringBean().getName()); assertEquals(42, nestedBean.getIntBean().getValue()); } + + @Test + void testLargeAllocations(){ + ContiguousList strings = new ContiguousList<>(String.class); + for (int i=0; i<1000; i++){ + strings.add("..................."); + } + + ContiguousList strings3 = new ContiguousList<>(String.class); + for (int i=0; i<1000; i++){ + strings3.add("..................."); + } + } } diff --git a/lib/src/test/java/nl/sanderhautvast/contiguous/DeepBean.java b/lib/src/test/java/com/github/shautvast/contiguous/DeepBean.java similarity index 86% rename from lib/src/test/java/nl/sanderhautvast/contiguous/DeepBean.java rename to lib/src/test/java/com/github/shautvast/contiguous/DeepBean.java index 9d954ba..a8f76e4 100644 --- a/lib/src/test/java/nl/sanderhautvast/contiguous/DeepBean.java +++ b/lib/src/test/java/com/github/shautvast/contiguous/DeepBean.java @@ -1,4 +1,4 @@ -package nl.sanderhautvast.contiguous; +package com.github.shautvast.contiguous; import lombok.AllArgsConstructor; import lombok.Data; diff --git a/lib/src/test/java/nl/sanderhautvast/contiguous/DoubleBean.java b/lib/src/test/java/com/github/shautvast/contiguous/DoubleBean.java similarity index 81% rename from lib/src/test/java/nl/sanderhautvast/contiguous/DoubleBean.java rename to lib/src/test/java/com/github/shautvast/contiguous/DoubleBean.java index 2b4bcaf..9ae3822 100644 --- a/lib/src/test/java/nl/sanderhautvast/contiguous/DoubleBean.java +++ b/lib/src/test/java/com/github/shautvast/contiguous/DoubleBean.java @@ -1,4 +1,4 @@ -package nl.sanderhautvast.contiguous; +package com.github.shautvast.contiguous; import lombok.AllArgsConstructor; import lombok.Data; diff --git a/lib/src/test/java/nl/sanderhautvast/contiguous/FloatBean.java b/lib/src/test/java/com/github/shautvast/contiguous/FloatBean.java similarity index 81% rename from lib/src/test/java/nl/sanderhautvast/contiguous/FloatBean.java rename to lib/src/test/java/com/github/shautvast/contiguous/FloatBean.java index e70c3c3..658e2de 100644 --- a/lib/src/test/java/nl/sanderhautvast/contiguous/FloatBean.java +++ b/lib/src/test/java/com/github/shautvast/contiguous/FloatBean.java @@ -1,4 +1,4 @@ -package nl.sanderhautvast.contiguous; +package com.github.shautvast.contiguous; import lombok.AllArgsConstructor; import lombok.Data; diff --git a/lib/src/test/java/nl/sanderhautvast/contiguous/IntBean.java b/lib/src/test/java/com/github/shautvast/contiguous/IntBean.java similarity index 81% rename from lib/src/test/java/nl/sanderhautvast/contiguous/IntBean.java rename to lib/src/test/java/com/github/shautvast/contiguous/IntBean.java index 07c87b8..bd863b5 100644 --- a/lib/src/test/java/nl/sanderhautvast/contiguous/IntBean.java +++ b/lib/src/test/java/com/github/shautvast/contiguous/IntBean.java @@ -1,4 +1,4 @@ -package nl.sanderhautvast.contiguous; +package com.github.shautvast.contiguous; import lombok.AllArgsConstructor; import lombok.Data; diff --git a/lib/src/test/java/nl/sanderhautvast/contiguous/LongBean.java b/lib/src/test/java/com/github/shautvast/contiguous/LongBean.java similarity index 81% rename from lib/src/test/java/nl/sanderhautvast/contiguous/LongBean.java rename to lib/src/test/java/com/github/shautvast/contiguous/LongBean.java index fd08cfb..16e61d7 100644 --- a/lib/src/test/java/nl/sanderhautvast/contiguous/LongBean.java +++ b/lib/src/test/java/com/github/shautvast/contiguous/LongBean.java @@ -1,4 +1,4 @@ -package nl.sanderhautvast.contiguous; +package com.github.shautvast.contiguous; import lombok.AllArgsConstructor; import lombok.Data; diff --git a/lib/src/test/java/nl/sanderhautvast/contiguous/NestedBean.java b/lib/src/test/java/com/github/shautvast/contiguous/NestedBean.java similarity index 84% rename from lib/src/test/java/nl/sanderhautvast/contiguous/NestedBean.java rename to lib/src/test/java/com/github/shautvast/contiguous/NestedBean.java index fb01307..30f23ed 100644 --- a/lib/src/test/java/nl/sanderhautvast/contiguous/NestedBean.java +++ b/lib/src/test/java/com/github/shautvast/contiguous/NestedBean.java @@ -1,4 +1,4 @@ -package nl.sanderhautvast.contiguous; +package com.github.shautvast.contiguous; import lombok.AllArgsConstructor; import lombok.Data; diff --git a/lib/src/test/java/com/github/shautvast/contiguous/NestedBeanHandler.java b/lib/src/test/java/com/github/shautvast/contiguous/NestedBeanHandler.java new file mode 100644 index 0000000..f9660d8 --- /dev/null +++ b/lib/src/test/java/com/github/shautvast/contiguous/NestedBeanHandler.java @@ -0,0 +1,11 @@ +package com.github.shautvast.contiguous; + +public class NestedBeanHandler extends CompoundTypeHandler{ + NestedBeanHandler(Class type) { + super(type); + } + + NestedBeanHandler(Class type, String propertyName) { + super(type, propertyName); + } +} diff --git a/lib/src/test/java/nl/sanderhautvast/contiguous/ShortBean.java b/lib/src/test/java/com/github/shautvast/contiguous/ShortBean.java similarity index 81% rename from lib/src/test/java/nl/sanderhautvast/contiguous/ShortBean.java rename to lib/src/test/java/com/github/shautvast/contiguous/ShortBean.java index 76906fe..0a37f31 100644 --- a/lib/src/test/java/nl/sanderhautvast/contiguous/ShortBean.java +++ b/lib/src/test/java/com/github/shautvast/contiguous/ShortBean.java @@ -1,4 +1,4 @@ -package nl.sanderhautvast.contiguous; +package com.github.shautvast.contiguous; import lombok.AllArgsConstructor; import lombok.Data; diff --git a/lib/src/test/java/nl/sanderhautvast/contiguous/StringBean.java b/lib/src/test/java/com/github/shautvast/contiguous/StringBean.java similarity index 82% rename from lib/src/test/java/nl/sanderhautvast/contiguous/StringBean.java rename to lib/src/test/java/com/github/shautvast/contiguous/StringBean.java index 16b59ed..a4f473d 100644 --- a/lib/src/test/java/nl/sanderhautvast/contiguous/StringBean.java +++ b/lib/src/test/java/com/github/shautvast/contiguous/StringBean.java @@ -1,4 +1,4 @@ -package nl.sanderhautvast.contiguous; +package com.github.shautvast.contiguous; import lombok.AllArgsConstructor; import lombok.Data; diff --git a/lib/src/test/java/com/github/shautvast/contiguous/asm/AsmContiguousListTest.java b/lib/src/test/java/com/github/shautvast/contiguous/asm/AsmContiguousListTest.java new file mode 100644 index 0000000..eb20490 --- /dev/null +++ b/lib/src/test/java/com/github/shautvast/contiguous/asm/AsmContiguousListTest.java @@ -0,0 +1,227 @@ +package com.github.shautvast.contiguous.asm; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +public class AsmContiguousListTest { + + @Test + public void testAddAndGetString() { + AsmContiguousList list = new AsmContiguousList<>(String.class); + assertTrue(list.isEmpty()); + + list.add("hitchhikersguide to the galaxy"); + assertFalse(list.isEmpty()); + assertEquals(1, list.size()); + + list.add("the publishing houses of Ursa Minor"); + assertFalse(list.isEmpty()); + assertEquals(2, list.size()); + + String title = list.get(0); + assertEquals("hitchhikersguide to the galaxy", title); + + String titleJson = list.getAsJson(0); + assertEquals("\"hitchhikersguide to the galaxy\"", titleJson); + + String publisher = list.get(1); + assertEquals("the publishing houses of Ursa Minor", publisher); + } + +// @Test +// public void testStringBean() { +// ContiguousList beanList = new ContiguousList<>(StringBean.class); +// beanList.add(new StringBean("Douglas Adams")); +// +// assertArrayEquals(new byte[]{39, 68, 111, 117, 103, 108, 97, 115, 32, 65, 100, 97, 109, 115}, beanList.getData()); +// +// StringBean douglas = beanList.get(0); +// assertEquals("Douglas Adams", douglas.getName()); +// +// String douglasJson = beanList.getAsJson(0); +// assertEquals("{\"name\": \"Douglas Adams\"}", douglasJson); +// +// // now add new data to see if existing data remains intact +// beanList.add(new StringBean("Ford Prefect")); +// +// assertEquals("Douglas Adams", beanList.get(0).getName()); +// assertEquals("Ford Prefect", beanList.get(1).getName()); +// +// assertEquals(2, beanList.size()); +// } +// +// @Test +// public void testIntBean() { +// ContiguousList beanList = new ContiguousList<>(IntBean.class); +// beanList.add(new IntBean(42)); +// +// assertArrayEquals(new byte[]{1, 42}, +// beanList.getData()); +// assertEquals(42, beanList.get(0).getValue()); +// } +// +// @Test +// public void testLong() { +// ContiguousList beanList = new ContiguousList<>(LongBean.class); +// beanList.add(new LongBean(42)); +// +// assertArrayEquals(new byte[]{1, 42}, +// beanList.getData()); +// assertEquals(42, beanList.get(0).getValue()); +// } +// +// @Test +// public void testShort() { +// ContiguousList beanList = new ContiguousList<>(ShortBean.class); +// beanList.add(new ShortBean((short) 42)); +// +// assertArrayEquals(new byte[]{1, 42}, +// beanList.getData()); +// } +// +// @Test +// public void testByte() { +// ContiguousList beanList = new ContiguousList<>(ByteBean.class); +// beanList.add(new ByteBean((byte) -42)); +// +// assertArrayEquals(new byte[]{1, -42}, +// beanList.getData()); +// } +// +// @Test +// public void testNestedBean() { +// ContiguousList beanList = new ContiguousList<>(NestedBean.class); +// beanList.add(new NestedBean(new StringBean("vogon constructor fleet"), new IntBean(42))); +// +// NestedBean expected = new NestedBean(new StringBean("vogon constructor fleet"), new IntBean(42)); +// assertEquals(expected, beanList.get(0)); +// } +// +// @Test +// public void testFloat() { +// ContiguousList beanList = new ContiguousList<>(FloatBean.class); +// beanList.add(new FloatBean(1.1F)); +// +// +// assertEquals(1.1F, beanList.get(0).getValue()); +// } +// +// @Test +// public void testDouble() { +// ContiguousList beanList = new ContiguousList<>(DoubleBean.class); +// beanList.add(new DoubleBean(1.1)); +// +// assertEquals(1.1, beanList.get(0).getValue()); +// } +// +// @Test +// public void testNullFloat() { +// ContiguousList beanList = new ContiguousList<>(FloatBean.class); +// beanList.add(new FloatBean(null)); +// +// assertNull(beanList.get(0).getValue()); +// } +// +// @Test +// public void testNullString() { +// ContiguousList beanList = new ContiguousList<>(StringBean.class); +// beanList.add(new StringBean(null)); +// +// assertNull(beanList.get(0).getName()); +// } +// +// @Test +// public void test100Elements() { +// ContiguousList beanList = new ContiguousList<>(StringBean.class); +// for (int i = 0; i < 100; i++) { +// beanList.add(new StringBean(null)); +// } +// assertEquals(100, beanList.size()); +// for (int i = 0; i < 100; i++) { +// assertNull(beanList.get(i).getName()); +// } +// } +// +// @Test +// public void testBigInteger() { +// ContiguousList bigIntegers = new ContiguousList<>(BigInteger.class); +// bigIntegers.add(new BigInteger("1000000000")); +// assertEquals(1_000_000_000L, bigIntegers.get(0).longValue()); +// } +// +// @Test +// public void testIterator() { +// ContiguousList integers = new ContiguousList<>(Integer.class); +// for (int i = 0; i < 100; i++) { +// integers.add(i); +// } +// int prevValue = -1; +// for (int value : integers) { +// assertEquals(prevValue, value - 1); +// prevValue = value; +// } +// +// integers.add(100); +// +// assertEquals(100, integers.get(100)); +// } +// +// @Test +// public void testPrimitiveIterator() { +// ContiguousList integers = new ContiguousList<>(Integer.class); +// for (int i = 0; i < 100; i++) { +// integers.add(i); +// } +// long prevValue = -1; +// for (Iterator intIter = integers.valueIterator(); intIter.hasNext(); ) { +// int value = (int) intIter.next(); +// assertEquals(prevValue, value - 1); +// prevValue = value; +// } +// +// +// integers.add(100); +// +// assertEquals(100, integers.get(100)); +// } +// +// @Test +// public void testCompoundValueIterator() { +// ContiguousList integers = new ContiguousList<>(IntBean.class); +// for (int i = 0; i < 100; i++) { +// integers.add(new IntBean(i)); +// } +// long prevValue = -1; +// for (Iterator intIter = integers.valueIterator(); intIter.hasNext(); ) { +// int value = (int) intIter.next(); +// assertEquals(prevValue, value - 1); +// prevValue = value; +// } +// +// +// integers.add(new IntBean(100)); +// +// assertEquals(new IntBean(100), integers.get(100)); // here an instance +// } +// +// +// +// @Test +// public void testSetterIterator() { +// ContiguousList integers = new ContiguousList<>(NestedBean.class); +// ContiguousList.SetterIterator iterator = integers.setterIterator(); +// +// if (iterator.hasNext()) { +// iterator.next().set("Magrathea"); +// } +// if (iterator.hasNext()) { +// iterator.next().set(42); +// } +// iterator.finishObject(); +// +// NestedBean nestedBean = integers.get(0); +// assertEquals("Magrathea", nestedBean.getStringBean().getName()); +// assertEquals(42, nestedBean.getIntBean().getValue()); +// } +} diff --git a/pom.xml b/pom.xml index 71163fa..cdc7afb 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - nl.sanderhautvast + com.github.shautvast contiguous-pom pom 1.0-SNAPSHOT @@ -13,6 +13,7 @@ demo jdbc jackson + benchmark contiguous contiguous storage for java