mirror of
https://github.com/OpenHFT/Chronicle-Map.git
synced 2021-09-13 01:26:12 +00:00
Merge remote-tracking branch 'origin/master'
This commit is contained in:
@@ -1,13 +1,13 @@
|
||||
*We can help you get Chronicle up and running in your organisation, we suggest you invite us in for
|
||||
consultancy, charged on an ad-hoc basis, we can discuss the best options tailored to your individual
|
||||
requirements. - [Contact Us](http://openhft.net/support/)*
|
||||
requirements. - [Contact Us](http://chronicle.software/support/)*
|
||||
|
||||
*Or you may already be using Chronicle and just want some help - [find out more..](http://openhft.net/support/)*
|
||||
*Or you may already be using Chronicle and just want some help - [find out more..](http://chronicle.software/support/)*
|
||||
|
||||
# Chronicle Map
|
||||
|
||||
A low latency replicated Key Value Store across your network, with eventual consistency, persistence and performance.
|
||||

|
||||

|
||||
|
||||
#### Maven Artifact Download
|
||||
```xml
|
||||
@@ -60,7 +60,7 @@ Click here to get the [Latest Version Number](http://search.maven.org/#search%7C
|
||||
* [Known Issues](https://github.com/OpenHFT/Chronicle-Map#known-issues)
|
||||
* [Stackoverflow](http://stackoverflow.com/tags/chronicle/info)
|
||||
* [Development Tasks - JIRA] (https://higherfrequencytrading.atlassian.net/browse/HCOLL)
|
||||
* [Use Case Which include Chronicle Map] (http://openhft.net/products/chronicle-engine/)
|
||||
* [Use Case Which include Chronicle Map] (http://chronicle.software/products/chronicle-engine/)
|
||||
|
||||
#### Examples
|
||||
|
||||
@@ -81,7 +81,7 @@ Click here to get the [Latest Version Number](http://search.maven.org/#search%7C
|
||||
Chronicle Map implements the interface `java.util.concurrent.ConcurrentMap`, however unlike the standard
|
||||
jdk implementations, ChronicleMap is both persistent and able to share your entries accross processes:
|
||||
|
||||

|
||||

|
||||
|
||||
## When to use HashMap, ConcurrentHashMap and ChronicleMap
|
||||
#### When to use HashMap
|
||||
@@ -118,7 +118,7 @@ SharedHashMap was the old name of what is now ChronicleMap. Since the last relea
|
||||
## Getting Started
|
||||
|
||||
#### Tutorial 1 - Creating an instance of Chronicle Map
|
||||
[](http://openhft.net/chronicle-map-video-tutorial-1/)
|
||||
[](http://chronicle.software/chronicle-map-video-tutorial-1/)
|
||||
|
||||
### Simple Construction
|
||||
|
||||
@@ -126,7 +126,7 @@ To download the JAR which contains Chronicle Map, we recommend you use maven, wh
|
||||
from [Maven Central](http://search.maven.org), once you have installed maven, all you have to do is
|
||||
add the following to your projects `pom.xml`:
|
||||
|
||||

|
||||

|
||||
|
||||
```xml
|
||||
<dependency>
|
||||
@@ -595,7 +595,7 @@ If after some business logic, in our example after reading the 'issueDate' and
|
||||
|
||||
## Serialization
|
||||
|
||||

|
||||

|
||||
|
||||
|
||||
ChronicleMap stores your data into off heap memory, so when you give it a Key or Value, it will
|
||||
@@ -615,7 +615,7 @@ an example of how to do this can be found at "IntValue$$Native"
|
||||
for a single type or a number of types.
|
||||
|
||||
### Import/Export entries as JSON
|
||||

|
||||

|
||||
|
||||
ChronicleMap supports importing and exporting all the entries into a JSON encoded file.
|
||||
|
||||
@@ -665,7 +665,7 @@ your JVM to crash. Close MUST BE the last thing that you do with the map.
|
||||
|
||||
ChronicleMap supports both TCP and UDP replication
|
||||
|
||||

|
||||

|
||||
|
||||
### TCP / UDP Background.
|
||||
TCP/IP is a reliable protocol, what this means is that unless you have a network failure or hardware
|
||||
@@ -824,7 +824,7 @@ this, in other words its a bidirectional connection.
|
||||
|
||||
### Configuring Three Way TCP/IP Replication
|
||||
|
||||

|
||||

|
||||
|
||||
Below is example how to set up tcpConfig for 3 host
|
||||
|
||||
@@ -865,7 +865,7 @@ is dropped and re-established.
|
||||
|
||||
# Multiple Chronicle Maps - Network Distributed
|
||||
|
||||

|
||||

|
||||
|
||||
ChronicleMap TCP Replication lets you distribute a single ChronicleMap, to a number of servers
|
||||
across your network. Replication is point to point and the data transfer is bidirectional, so in the
|
||||
@@ -1034,7 +1034,7 @@ favoriteColourServer1.close();
|
||||
|
||||
# Stateless Client
|
||||
|
||||

|
||||

|
||||
|
||||
A stateless client is an instance of a `ChronicleMap` or a `ChronicleSet` that does not hold any
|
||||
data
|
||||
@@ -1043,7 +1043,7 @@ data
|
||||
holds all your data, the server can not it’s self be a stateless client. Your stateless client must
|
||||
be connected to the server via TCP/IP.
|
||||
|
||||

|
||||

|
||||
|
||||
The stateless client delegates all your method calls to
|
||||
the remote server. The stateless client operations will block, in other words the stateless
|
||||
@@ -1126,7 +1126,7 @@ When calling the stateless client, you will get better throughput if you invoke
|
||||
by the server. Your stateless client will block until an acknowledgement has been received from the server that
|
||||
the event was processed.
|
||||
|
||||

|
||||

|
||||
|
||||
When you are calling methods that return a value like get() this
|
||||
blocking adds no additional overhead, because you have to wait for the return value anyway,
|
||||
|
||||
@@ -0,0 +1,257 @@
|
||||
package net.openhft.chronicle.map;
|
||||
|
||||
import net.openhft.chronicle.hash.function.SerializableFunction;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.*;
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* Created by daniel on 22/04/15.
|
||||
*/
|
||||
public class FilePerKeyMap<K, V> implements ChronicleMap<K, V> {
|
||||
private String dir;
|
||||
private Path dirPath;
|
||||
|
||||
public FilePerKeyMap(String dir) {
|
||||
try {
|
||||
dirPath = Paths.get(dir);
|
||||
Files.createDirectories(dirPath);
|
||||
} catch (IOException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
this.dir = dir;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return (int)getFiles(dirPath).count();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return size()==0 ? true: false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsKey(Object key) {
|
||||
return getFiles(dirPath).anyMatch(p->p.getFileName().toString().equals(key));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsValue(Object value) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public V get(Object key) {
|
||||
checkTypeIsString(key);
|
||||
|
||||
Path path = Paths.get(dir,(String)key);
|
||||
return (V)getFileContents(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public V put(K key, V value) {
|
||||
checkTypeIsString(key, value);
|
||||
|
||||
Path path = Paths.get(dir,(String)key);
|
||||
String existingValue = getFileContents(path);
|
||||
writeToFile(path, (String) value);
|
||||
|
||||
return (V) existingValue;
|
||||
}
|
||||
|
||||
private Stream<Path> getFiles(Path path){
|
||||
try {
|
||||
return Files.walk(path).filter(p -> !Files.isDirectory(p));
|
||||
} catch (IOException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
private String getFileContents(Path path){
|
||||
String existingValue = null;
|
||||
if(Files.exists(path)) {
|
||||
try {
|
||||
existingValue = Files.readAllLines(path).stream().collect(Collectors.joining());
|
||||
} catch (IOException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
return existingValue;
|
||||
}
|
||||
|
||||
private void writeToFile(Path path, String value){
|
||||
try {
|
||||
Files.write(path, value.getBytes(), StandardOpenOption.CREATE,
|
||||
StandardOpenOption.TRUNCATE_EXISTING,
|
||||
StandardOpenOption.WRITE);
|
||||
} catch (IOException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void deleteFile(Path path){
|
||||
try {
|
||||
Files.delete(path);
|
||||
} catch (IOException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public V remove(Object key) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putAll(Map<? extends K, ? extends V> m) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
getFiles(dirPath).forEach(this::deleteFile);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Set<K> keySet() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Collection<V> values() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Set<Entry<K, V>> entrySet() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public V getUsing(K key, V usingValue) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public V acquireUsing(@NotNull K key, V usingValue) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public MapKeyContext<K, V> acquireContext(@NotNull K key, @NotNull V usingValue) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <R> R getMapped(K key, @NotNull SerializableFunction<? super V, R> function) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public V putMapped(K key, @NotNull UnaryOperator<V> unaryOperator) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getAll(File toFile) throws IOException {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putAll(File fromFile) throws IOException {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public V newValueInstance() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public K newKeyInstance() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<V> valueClass() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public File file() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long longSize() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MapKeyContext<K, V> context(K key) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<K> keyClass() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean forEachEntryWhile(Predicate<? super MapKeyContext<K, V>> predicate) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void forEachEntry(Consumer<? super MapKeyContext<K, V>> action) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public V putIfAbsent(K key, V value) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove(Object key, Object value) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean replace(K key, V oldValue, V newValue) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public V replace(K key, V value) {
|
||||
return null;
|
||||
}
|
||||
|
||||
private void checkTypeIsString(Object... objs) {
|
||||
for(Object o : objs){
|
||||
if(!(o instanceof String))
|
||||
throw new AssertionError("FilePerKeyMap only accepts Key and Values " +
|
||||
"of type String. Unsupported type: '" + o + "'");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package net.openhft.chronicle.map;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* JUnit test class to support {@link net.openhft.chronicle.map.FilePerMapKeyTest}
|
||||
*/
|
||||
public class FilePerMapKeyTest {
|
||||
/**
|
||||
* FilePerMapKey only works with Strings
|
||||
*/
|
||||
@Test(expected = AssertionError.class)
|
||||
public void testWrongType(){
|
||||
FilePerKeyMap<Integer, String> map = new FilePerKeyMap<>("/tmp/filepermaptests");
|
||||
map.put(1, "test");
|
||||
}
|
||||
|
||||
/**
|
||||
* Testing the put
|
||||
*/
|
||||
@Test
|
||||
public void testPut(){
|
||||
//There are no entries in the map so null should be returned
|
||||
FilePerKeyMap<String, String> map = new FilePerKeyMap<>("/tmp/filepermaptests");
|
||||
//just in case it hasn't been cleared up last time
|
||||
map.clear();
|
||||
|
||||
String val = map.put("one", "test1");
|
||||
assertEquals(val, null);
|
||||
|
||||
//After the entry has been written the value returned should be
|
||||
//the previous value
|
||||
val = map.put("one", "test2");
|
||||
assertEquals(val, "test1");
|
||||
|
||||
//Check that get returns the latest value
|
||||
val = map.get("one");
|
||||
assertEquals("test2", val);
|
||||
|
||||
assertTrue(map.containsKey("one"));
|
||||
assertFalse(map.containsKey("two"));
|
||||
|
||||
//Check the size is one
|
||||
int size = map.size();
|
||||
assertEquals(1,size);
|
||||
assertFalse(map.isEmpty());
|
||||
|
||||
map.clear();
|
||||
//Check the size is now 0
|
||||
size = map.size();
|
||||
assertEquals(0, size);
|
||||
|
||||
assertTrue(map.isEmpty());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user