diff --git a/examples/B/.gitignore b/examples/B/.gitignore
index 3c3d84c..1930020 100644
--- a/examples/B/.gitignore
+++ b/examples/B/.gitignore
@@ -1 +1,3 @@
pmemkv
+__pycache__/
+target/
diff --git a/examples/B/Makefile b/examples/B/Makefile
index 59ec509..b0a0e0c 100644
--- a/examples/B/Makefile
+++ b/examples/B/Makefile
@@ -11,13 +11,17 @@ pmemkv: $(OBJS)
$(CXX) $(CXXFLAGS) -o $@ $(OBJS) $(LIBS)
# for the Python script, the build step just checks for syntax errors
-kv: kv.py
+python: kv.py
python3 -m py_compile kv.py
+java:
+ $(MAKE) -C PmemkvExample java
+
clean:
$(RM) *.o core a.out
clobber: clean
- $(RM) pmemkv
+ $(RM) -r pmemkv __pycache__/
+ $(MAKE) -C PmemkvExample clobber
-.PHONY: all clean clobber
+.PHONY: all clean clobber java
diff --git a/examples/B/PmemkvExample/Makefile b/examples/B/PmemkvExample/Makefile
new file mode 100644
index 0000000..99a3e8b
--- /dev/null
+++ b/examples/B/PmemkvExample/Makefile
@@ -0,0 +1,11 @@
+#
+# Makefile for java pmemkv example
+#
+
+java:
+ mvn package
+
+clobber:
+ $(RM) -r target/
+
+.PHONY: clobber java
diff --git a/examples/B/PmemkvExample/pom.xml b/examples/B/PmemkvExample/pom.xml
new file mode 100644
index 0000000..00512d7
--- /dev/null
+++ b/examples/B/PmemkvExample/pom.xml
@@ -0,0 +1,80 @@
+
+
+ 4.0.0
+
+ io.pmem
+ PmemkvExample
+ 1.2.0
+ Example for pmemkv Java binding
+ jar
+
+
+
+
+ io.pmem
+ pmemkv
+ [1.2.0,)
+
+
+
+
+
+ 1.8
+ 1.8
+ UTF-8
+ UTF-8
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 3.8.1
+
+ true
+ false
+
+ -Xlint:all
+
+
+
+
+ org.apache.maven.plugins
+ maven-jar-plugin
+ 3.2.0
+
+
+
+ true
+ ${project.artifactId}
+
+
+
+
+
+ maven-assembly-plugin
+
+
+ package
+
+ single
+
+
+
+
+
+ jar-with-dependencies
+
+
+
+ ${project.artifactId}
+
+
+
+
+
+
+
diff --git a/examples/B/PmemkvExample/src/main/java/PmemkvExample.java b/examples/B/PmemkvExample/src/main/java/PmemkvExample.java
new file mode 100644
index 0000000..04ee22d
--- /dev/null
+++ b/examples/B/PmemkvExample/src/main/java/PmemkvExample.java
@@ -0,0 +1,79 @@
+import io.pmem.pmemkv.Converter;
+import io.pmem.pmemkv.Database;
+import io.pmem.pmemkv.NotFoundException;
+
+import java.nio.ByteBuffer;
+
+/*
+ * Implementation of Converter interface to allow
+ * storing in the Database keys and values as Strings.
+ */
+class StringConverter implements Converter {
+ public ByteBuffer toByteBuffer(String entry) {
+ return ByteBuffer.wrap(entry.getBytes());
+ }
+
+ public String fromByteBuffer(ByteBuffer entry) {
+ byte[] bytes;
+ bytes = new byte[entry.capacity()];
+ entry.get(bytes);
+ return new String(bytes);
+ }
+}
+
+public class PmemkvExample {
+ /*
+ * this is the main program, used this way:
+ * java PmemkvExample pmemfile -- print all the keys and values in the pmemfile
+ * java PmemkvExample pmemfile key -- lookup key and print the value
+ * java PmemkvExample pmemfile key value -- add a key/value pair to the pmemfile
+ *
+ * the pmemfile is created automatically if it doesn't already exist.
+ */
+
+ public static void main(String[] args) {
+ int SIZE = 10 * 1024 * 1024; // 10 MiB
+ String ENGINE = "cmap";
+
+ if (args.length < 1 || args.length > 3) {
+ System.err.println("Usage: java PmemkvExample kvfile [key [value]]");
+ System.exit(1);
+ }
+
+ /*
+ * Configure and open Database, using Builder.
+ * Part of the configuration is given (as an example) as JSON Object.
+ * Note, it is required to define key and value converter (to/from ByteBuffer).
+ */
+ Database db = new Database.Builder(ENGINE)
+ .fromJson("{\"path\":\"" + args[0] + "\", \"create_if_missing\":1}")
+ .setSize(SIZE)
+ .setKeyConverter(new StringConverter())
+ .setValueConverter(new StringConverter())
+ .build();
+
+ if (args.length == 1) {
+
+ // iterate through the key-value store, printing them
+ db.getAll((String k, String v) -> {
+ System.out.println(k + "=\"" + v + "\"");
+ });
+ } else if (args.length == 2) {
+
+ // lookup the given key and print the value
+ try {
+ db.get(args[1], (String v) -> {
+ System.out.println(args[1] + "=\"" + v + "\"");
+ });
+ } catch (NotFoundException e) {
+ System.out.println("Key '" + args[1] + "' wasn't found in DB");
+ }
+ } else {
+
+ // add the given key-value pair
+ db.put(args[1], args[2]);
+ }
+
+ db.stop();
+ }
+}
diff --git a/examples/B/README.txt b/examples/B/README.txt
index 33d8135..afb6186 100644
--- a/examples/B/README.txt
+++ b/examples/B/README.txt
@@ -7,23 +7,36 @@ this example is recommended for everyone since it provides an overview
of how the most common libraries are used together.
The pmemkv.cpp program uses the C++ language bindings for libpmemkv,
-and kv.py program uses the Python language bindings. The programs
-are very simple, so even people who are not that familiar with C++
-and Python should be able to understand them.
+kv.py program uses the Python language bindings, and PmemkvExample is
+a simple project using the Java bindings. The programs are
+very simple, so even people who are not that familiar with C++, Python,
+and Java should be able to understand them.
-This is example consists of these files:
+This example consists of these files:
-pmemkv.cpp -- simple C++ program using libpmemkv
-kvinit.cpp -- convenient function for creating/opening the kv store
-Makefile -- rules for building this example
-kv.py -- simple Python program using libpmemkv
-run_cpp.sh -- script to run the C++ version
-run_py.sh -- script to run the Python version
+pmemkv.cpp -- simple C++ program using libpmemkv
+kvinit.cpp -- convenient function for creating/opening the kv store
+Makefile -- rules for building this example
+kv.py -- simple Python program using libpmemkv
+PmemkvExample/ -- simple Java project with its files:
+ Makefile -- rules for building the Java example
+ pom.xml -- project and dependencies configuration
+ PmemkvExample.java -- source file (located in sub-dir src/main/java)
+run_cpp.sh -- script to run the C++ version
+run_py.sh -- script to run the Python version
+run_java.sh -- script to run the Java version
+run_cross_lang.sh -- script executing all languages alternatively
To build this example run: make
-To run it and see what it illustrates run: ./run_cpp.sh or ./run_py.sh
+To run it and see what it illustrates run:
+./run_cpp.sh, ./run_py.sh or ./run_java.sh
-Modifying the code and run steps is a great way to learn from this example.
+The last script - run_cross_lang.sh - shows how data in the same
+database can be accessed using various programs, even implemented
+in different programming languages. This will work in pmemkv
+as long as they use the same engine.
+
+Modifying the code and running steps is a great way to learn from this example.
This example shows a generic key-value store, called libpmemkv, which
handles all the details of persistent memory for you. Each "put"
@@ -38,7 +51,7 @@ This example uses:
- the "cmap" persistent memory concurrent hashmap, which uses:
- libpmemobj for allocation & transactions, which uses:
- libpmem for low-level mapping and flushing, which uses:
- - a DAX-mounted file system to get direct access to pmem
+ - a DAX-mounted file system to get direct access to pmem.
Although the above stack seems like lots of SW, it is all designed to
give applications direct access to their data where sits in pmem, rather
diff --git a/examples/B/kv.py b/examples/B/kv.py
index 78f85ae..8ecb8ec 100755
--- a/examples/B/kv.py
+++ b/examples/B/kv.py
@@ -11,9 +11,9 @@ def kvprint(key, value):
#
# this is the main program, used this way:
-# kv pmemfile -- print all the keys and values in the pmemfile
-# kv pmemfile key -- lookup key and print the value
-# kv pmemfile key value -- add a key/value pair to the pmemfile
+# kv.py pmemfile -- print all the keys and values in the pmemfile
+# kv.py pmemfile key -- lookup key and print the value
+# kv.py pmemfile key value -- add a key/value pair to the pmemfile
#
# the pmemfile is created automatically if it doesn't already exist.
#
@@ -32,11 +32,16 @@ def kvprint(key, value):
if len(sys.argv) == 2:
# iterate through the key-value store, printing them
db.get_all(kvprint)
+
elif len(sys.argv) == 3:
# lookup the given key and print the value
- db.get(sys.argv[2],
- lambda value:
- print(f"{sys.argv[2]}=\"{memoryview(value).tobytes().decode()}\""))
+ try:
+ db.get(sys.argv[2],
+ lambda value:
+ print(f"{sys.argv[2]}=\"{memoryview(value).tobytes().decode()}\""))
+ except KeyError:
+ print(f"Key '{sys.argv[2]}' wasn't found in DB")
+
else:
# add the given key-value pair
db.put(sys.argv[2], sys.argv[3])
diff --git a/examples/B/kvinit.cpp b/examples/B/kvinit.cpp
index 8cfa3c5..40900a6 100644
--- a/examples/B/kvinit.cpp
+++ b/examples/B/kvinit.cpp
@@ -1,23 +1,20 @@
#include
-#include
#include
#include
using namespace pmem::kv;
using std::cerr;
-using std::cout;
using std::endl;
-using std::string;
// default size for this example: 10 Meg
const uint64_t SIZE = 10 * 1024 * 1024;
//
-// must_open_or_create() is a convenience function to open the
+// open_or_create() is a convenience function to open the
// database if it already exists, or create it with a default
// size if it doesn't.
//
-db *must_open_or_create(const char *path) {
+db *open_or_create(const char *path) {
// start by creating the db object
db *kv = new db();
@@ -26,29 +23,28 @@ db *must_open_or_create(const char *path) {
// create the config information for the pmemkv open
config cfg;
- if (cfg.put_string("path", path) != status::OK) {
+ // flag to control the behavior for open (create) method
+ if (cfg.put_create_if_missing(true) != status::OK) {
cerr << pmemkv_errormsg() << endl;
exit(1);
}
- if (!std::filesystem::exists(path)) {
- // file doesn't exist, so add config flags to create it
- if (cfg.put_uint64("force_create", 1) != status::OK) {
- cerr << pmemkv_errormsg() << endl;
- exit(1);
- }
-
- if (cfg.put_uint64("size", SIZE) != status::OK) {
- cerr << pmemkv_errormsg() << endl;
- exit(1);
- }
+ // specify path of DB
+ if (cfg.put_path(path) != status::OK) {
+ cerr << pmemkv_errormsg() << endl;
+ exit(1);
+ }
+
+ // if file doesn't exist, we need to specify size of DB to create
+ if (cfg.put_size(SIZE) != status::OK) {
+ cerr << pmemkv_errormsg() << endl;
+ exit(1);
}
if (kv->open("cmap", std::move(cfg)) != status::OK) {
- cerr << errormsg() << endl;
+ cerr << pmemkv_errormsg() << endl;
exit(1);
}
return kv;
-
}
diff --git a/examples/B/pmemkv.cpp b/examples/B/pmemkv.cpp
index 1cae85d..c1c1014 100644
--- a/examples/B/pmemkv.cpp
+++ b/examples/B/pmemkv.cpp
@@ -5,9 +5,8 @@ using namespace pmem::kv;
using std::cerr;
using std::cout;
using std::endl;
-using std::string;
-db *must_open_or_create(const char *path);
+db *open_or_create(const char *path);
//
// kvprint is a callback function to process each key/value pair. it is
@@ -18,7 +17,6 @@ int kvprint(string_view k, string_view v) {
cout << k.data() << "=\"" << v.data() << "\"" << endl;
return 0;
-
}
//
@@ -37,7 +35,7 @@ int main(int argc, char *argv[]) {
exit(1);
}
- db *kv = must_open_or_create(argv[1]);
+ db *kv = open_or_create(argv[1]);
if (argc == 2) {
@@ -50,19 +48,20 @@ int main(int argc, char *argv[]) {
auto ret = kv->get(argv[2], [&](string_view value) {
cout << argv[2] << "=\"" << value.data() << "\"" << endl;
});
- if (ret != status::OK) {
- cerr << errormsg() << endl;
+ if (ret != status::OK && ret != status::NOT_FOUND) {
+ cerr << pmemkv_errormsg() << endl;
exit(1);
+ } else if (ret == status::NOT_FOUND) {
+ cout << "Key \"" << argv[2] << "\" wasn't found in DB" << endl;
}
} else {
// add the given key-value pair
if (kv->put(argv[2], argv[3]) != status::OK) {
- cerr << errormsg() << endl;
+ cerr << pmemkv_errormsg() << endl;
exit(1);
}
-
}
// stop the pmemkv engine
diff --git a/examples/B/run_cpp.sh b/examples/B/run_cpp.sh
index e5d4639..21e68c0 100755
--- a/examples/B/run_cpp.sh
+++ b/examples/B/run_cpp.sh
@@ -3,20 +3,24 @@
# shell commands to run the C++ version of this example
#
+my_kvfile=/pmem/kvfile
+
# remove file if left over from previous run
-rm -f /pmem/kvfile
+rm -f $my_kvfile
# add some values
-./pmemkv /pmem/kvfile bach 1685-1750
-./pmemkv /pmem/kvfile mozart 1756-1791
+./pmemkv $my_kvfile bach 1685-1750
+./pmemkv $my_kvfile mozart 1756-1791
# print a value
-./pmemkv /pmem/kvfile bach
+./pmemkv $my_kvfile bach
+# print a non-existent value
+./pmemkv $my_kvfile chopin
# add some more
-./pmemkv /pmem/kvfile beethoven 1770-1827
-./pmemkv /pmem/kvfile brahms 1833-1897
-./pmemkv /pmem/kvfile haydn 1732-1809
+./pmemkv $my_kvfile beethoven 1770-1827
+./pmemkv $my_kvfile brahms 1833-1897
+./pmemkv $my_kvfile haydn 1732-1809
# print all k-v pairs in kvfile
-./pmemkv /pmem/kvfile
+./pmemkv $my_kvfile
diff --git a/examples/B/run_cross_lang.sh b/examples/B/run_cross_lang.sh
new file mode 100755
index 0000000..957bf2b
--- /dev/null
+++ b/examples/B/run_cross_lang.sh
@@ -0,0 +1,30 @@
+#!/bin/bash -ex
+#
+# shell commands to run this example using multiple language bindings
+# alternatively. All examples use the same engine and can be used
+# intertwined to access the same data (in the same kv file).
+#
+
+jexec='java -cp ./target/PmemkvExample-1.2.0-jar-with-dependencies.jar PmemkvExample'
+my_kvfile=/pmem/kvfile
+
+# remove file if left over from previous run
+rm -f $my_kvfile
+
+
+## add some values using Python
+./kv.py $my_kvfile bach 1685-1750
+./kv.py $my_kvfile mozart 1756-1791
+./kv.py $my_kvfile beethoven 1770-1827
+
+
+# print some values using Java
+cd PmemkvExample
+$jexec $my_kvfile bach
+$jexec $my_kvfile chopin
+cd ..
+
+# add some more values and print all using C++
+./pmemkv $my_kvfile brahms 1833-1897
+./pmemkv $my_kvfile haydn 1732-1809
+./pmemkv $my_kvfile
diff --git a/examples/B/run_java.sh b/examples/B/run_java.sh
new file mode 100755
index 0000000..250fc96
--- /dev/null
+++ b/examples/B/run_java.sh
@@ -0,0 +1,30 @@
+#!/bin/bash -ex
+#
+# shell commands to run the Java version of this example
+#
+
+cd PmemkvExample
+jexec='java -cp ./target/PmemkvExample-1.2.0-jar-with-dependencies.jar PmemkvExample'
+my_kvfile=/pmem/kvfile
+
+# remove file if left over from previous run
+rm -f $my_kvfile
+
+# add some values
+$jexec $my_kvfile bach 1685-1750
+$jexec $my_kvfile mozart 1756-1791
+
+# print a value
+$jexec $my_kvfile bach
+# print a non-existent value
+$jexec $my_kvfile chopin
+
+# add some more
+$jexec $my_kvfile beethoven 1770-1827
+$jexec $my_kvfile brahms 1833-1897
+$jexec $my_kvfile haydn 1732-1809
+
+# print all k-v pairs in kvfile
+$jexec $my_kvfile
+
+cd ..
diff --git a/examples/B/run_py.sh b/examples/B/run_py.sh
index debe833..bb26f81 100755
--- a/examples/B/run_py.sh
+++ b/examples/B/run_py.sh
@@ -1,22 +1,26 @@
#!/bin/bash -ex
#
-# shell commands to run the C++ version of this example
+# shell commands to run the Python version of this example
#
+my_kvfile=/pmem/kvfile
+
# remove file if left over from previous run
-rm -f /pmem/kvfile
+rm -f $my_kvfile
# add some values
-./kv.py /pmem/kvfile bach 1685-1750
-./kv.py /pmem/kvfile mozart 1756-1791
+./kv.py $my_kvfile bach 1685-1750
+./kv.py $my_kvfile mozart 1756-1791
# print a value
-./kv.py /pmem/kvfile bach
+./kv.py $my_kvfile bach
+# print a non-existent value
+./kv.py $my_kvfile chopin
# add some more
-./kv.py /pmem/kvfile beethoven 1770-1827
-./kv.py /pmem/kvfile brahms 1833-1897
-./kv.py /pmem/kvfile haydn 1732-1809
+./kv.py $my_kvfile beethoven 1770-1827
+./kv.py $my_kvfile brahms 1833-1897
+./kv.py $my_kvfile haydn 1732-1809
# print all k-v pairs in kvfile
-./kv.py /pmem/kvfile
+./kv.py $my_kvfile