Add satisfies() and cleanup() to repository servers
diff --git a/src/main/java/com/intel/jndn/utils/RepositoryServer.java b/src/main/java/com/intel/jndn/utils/RepositoryServer.java
index 0364eb7..88219d8 100644
--- a/src/main/java/com/intel/jndn/utils/RepositoryServer.java
+++ b/src/main/java/com/intel/jndn/utils/RepositoryServer.java
@@ -27,12 +27,15 @@
public interface RepositoryServer extends Server {
/**
- * Store a {@link Data} packet in the server's repository until requested. The
- * task of removing (or retaining) stale packets is not specified here but
- * left to the implementation.
+ * Store a {@link Data} packet in the server's repository until requested.
*
* @param data the {@link Data} packet to store and serve
* @throws IOException if the underlying server fails to store the packet
*/
public void serve(Data data) throws IOException;
+
+ /**
+ * Clean up stale {@link Data} packets from the underlying content store.
+ */
+ public void cleanup();
}
diff --git a/src/main/java/com/intel/jndn/utils/SegmentedServer.java b/src/main/java/com/intel/jndn/utils/SegmentedServer.java
index c5cfec5..d89f445 100644
--- a/src/main/java/com/intel/jndn/utils/SegmentedServer.java
+++ b/src/main/java/com/intel/jndn/utils/SegmentedServer.java
@@ -58,11 +58,16 @@
register();
}
- InputStream stream = new ByteArrayInputStream(data.getContent().getImmutableArray());
- List<Data> segments = SegmentedServerHelper.segment(data, stream);
- for (Data segment : segments) {
- logger.info("Added segment: " + segment.getName().toUri());
- repository.put(segment);
+ if (data.getContent().size() >= SegmentedServerHelper.DEFAULT_SEGMENT_SIZE) {
+ InputStream stream = new ByteArrayInputStream(data.getContent().getImmutableArray());
+ List<Data> segments = SegmentedServerHelper.segment(data, stream);
+ for (Data segment : segments) {
+ logger.fine("Adding segment: " + segment.getName().toUri());
+ repository.put(segment);
+ }
+ } else {
+ logger.fine("Adding segment: " + data.getName().toUri());
+ repository.put(data);
}
}
@@ -71,6 +76,8 @@
*/
@Override
public void onInterest(Name prefix, Interest interest, Transport transport, long registeredPrefixId) {
+ logger.finer("Serving packet for: " + interest.toUri());
+
if (interest.getChildSelector() == -1) {
try {
interest.getName().get(-1).toSegment();
@@ -85,7 +92,15 @@
ByteBuffer buffer = data.wireEncode().buf();
transport.send(buffer);
} catch (Exception e) {
- logger.log(Level.SEVERE, "Failed to send data for: " + interest.toUri(), e);
+ logger.log(Level.SEVERE, "Failed to find data satisfying: " + interest.toUri(), e);
}
}
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void cleanup() {
+ repository.cleanup();
+ }
}
diff --git a/src/main/java/com/intel/jndn/utils/repository/ForLoopRepository.java b/src/main/java/com/intel/jndn/utils/repository/ForLoopRepository.java
index 1563c24..8f8ed5b 100644
--- a/src/main/java/com/intel/jndn/utils/repository/ForLoopRepository.java
+++ b/src/main/java/com/intel/jndn/utils/repository/ForLoopRepository.java
@@ -50,6 +50,7 @@
if (interest.matchesName(record.data.getName())) {
if (hasNoChildSelector(interest) && hasAcceptableFreshness(interest, record)) {
selectedData = record.data;
+ break;
} else {
Name.Component component = getNextComponentAfterLastInterestComponent(record.data, interest);
@@ -102,19 +103,14 @@
}
}
+ /**
+ * @param interest the {@link Interest} to check
+ * @return true if the {@link Interest} has no child selector
+ */
private static boolean hasNoChildSelector(Interest interest) {
return interest.getChildSelector() < 0;
}
- @Override
- public void cleanup() {
- for (int i = storage.size() - 1; i >= 0; i--) {
- if (!isFresh(storage.get(i))) {
- storage.remove(i);
- }
- }
- }
-
/**
* Check if a record is fresh.
*
@@ -144,6 +140,33 @@
}
/**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean satisfies(Interest interest) {
+ for (Record record : storage) {
+ if (interest.matchesName(record.data.getName()) && hasAcceptableFreshness(interest, record)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void cleanup() {
+ for (int i = storage.size() - 1; i >= 0; i--) {
+ if (!isFresh(storage.get(i))) {
+ synchronized (storage) {
+ storage.remove(i);
+ }
+ }
+ }
+ }
+
+ /**
* Helper data structure
*/
private class Record {
diff --git a/src/main/java/com/intel/jndn/utils/repository/Repository.java b/src/main/java/com/intel/jndn/utils/repository/Repository.java
index f64c145..ab9a127 100644
--- a/src/main/java/com/intel/jndn/utils/repository/Repository.java
+++ b/src/main/java/com/intel/jndn/utils/repository/Repository.java
@@ -41,6 +41,16 @@
public Data get(Interest interest) throws DataNotFoundException;
/**
+ * Check if this repository can satisfy the {@link Interest} with a
+ * {@link Data} packet; this should check not only name matching but freshness
+ * and any other selectors.
+ *
+ * @param interest the {@link Interest} to attempt to satisfy
+ * @return true if a {@link Data} exists that satisfies the {@link Interest}
+ */
+ public boolean satisfies(Interest interest);
+
+ /**
* Remove all stale {@link Data} packets from the repository.
*/
public void cleanup();
diff --git a/src/test/java/com/intel/jndn/utils/SegmentedServerTest.java b/src/test/java/com/intel/jndn/utils/SegmentedServerTest.java
index a840cd0..b6d271b 100644
--- a/src/test/java/com/intel/jndn/utils/SegmentedServerTest.java
+++ b/src/test/java/com/intel/jndn/utils/SegmentedServerTest.java
@@ -16,6 +16,7 @@
import com.intel.jndn.mock.MockFace;
import java.io.IOException;
import net.named_data.jndn.Data;
+import net.named_data.jndn.Interest;
import net.named_data.jndn.Name;
import net.named_data.jndn.util.Blob;
import static org.junit.Assert.*;
@@ -57,4 +58,40 @@
assertEquals(in.getName().toUri(), out.getName().toUri());
assertEquals("1234", out.getContent().toString());
}
+
+ @Test(expected = IOException.class)
+ public void testCleanup() throws Exception{
+ Data in = new Data(new Name("/test"));
+ in.getMetaInfo().setFreshnessPeriod(0);
+ instance.serve(in);
+ Thread.sleep(10);
+
+ Data out = SegmentedClient.getDefault().getSync(face, new Name("/test"));
+ assertNotNull(out);
+ assertEquals(in.getName(), out.getName());
+
+ instance.cleanup();
+ SegmentedClient.getDefault().getSync(face, new Name("/test"));
+ }
+
+ @Test
+ public void testServingNoContent() throws IOException{
+ instance.serve(new Data());
+ }
+
+ @Test
+ public void testWhenDataNameIsLongerThanInterestName() throws Exception{
+ instance.serve(new Data(new Name("/test/prefix/a/b/c/1")));
+ instance.serve(new Data(new Name("/test/prefix/a/b/c/2")));
+
+ Interest interest = new Interest(new Name("/test/prefix/a/b"))
+ .setChildSelector(Interest.CHILD_SELECTOR_RIGHT).setInterestLifetimeMilliseconds(100);
+ Data out = SegmentedClient.getDefault().getSync(face, interest);
+
+ assertNotNull(out);
+ assertEquals("/test/prefix/a/b/c/1", out.getName().toUri());
+ // note that this won't be .../c/2 since .../c/1 satisfies both the Interest
+ // name and "c" is the rightmost component (child selectors operate on the
+ // next component after the Interest name only)
+ }
}
diff --git a/src/test/java/com/intel/jndn/utils/repository/RepositoryTest.java b/src/test/java/com/intel/jndn/utils/repository/RepositoryTest.java
index 36fed91..f39e028 100644
--- a/src/test/java/com/intel/jndn/utils/repository/RepositoryTest.java
+++ b/src/test/java/com/intel/jndn/utils/repository/RepositoryTest.java
@@ -54,6 +54,16 @@
Data data2 = instance.get(interest2);
assertEquals("/a/b/c/e", data2.getName().toUri());
}
+
+ @Test
+ public void testChildSelectorsOnExactMatch() throws DataNotFoundException{
+ instance.put(buildData("/a/b/c"));
+ instance.put(buildData("/a/b/d"));
+
+ Interest interest = buildInterest("/a/b/c").setChildSelector(Interest.CHILD_SELECTOR_LEFT);
+ assertTrue(instance.satisfies(interest));
+ assertEquals("/a/b/c", instance.get(interest).getName().toUri());
+ }
@Test(expected = DataNotFoundException.class)
public void testFailure() throws DataNotFoundException {
@@ -80,4 +90,31 @@
interest.setMustBeFresh(true);
instance.get(interest);
}
+
+ @Test
+ public void testSatisfies() throws InterruptedException {
+ instance.put(RepoHelper.buildAlmostStaleData("/stale/data"));
+ instance.put(RepoHelper.buildFreshData("/fresh/data"));
+
+ Thread.sleep(10);
+
+ assertTrue(instance.satisfies(buildInterest("/fresh/data")));
+ assertFalse(instance.satisfies(buildInterest("/stale/data")));
+ assertFalse(instance.satisfies(buildInterest("/not/found/data")));
+ }
+
+ @Test
+ public void testChildSelectors() throws DataNotFoundException {
+ instance.put(RepoHelper.buildFreshData("/a/a"));
+ instance.put(RepoHelper.buildFreshData("/a/b/c/1"));
+ instance.put(RepoHelper.buildFreshData("/a/b/c/2"));
+ instance.put(RepoHelper.buildFreshData("/a/b/c/3"));
+
+ assertTrue(instance.satisfies(buildInterest("/a")));
+
+ Data out = instance.get(buildInterest("/a").setChildSelector(Interest.CHILD_SELECTOR_RIGHT));
+ assertEquals("/a/b/c/1", out.getName().toUri());
+ // you may think this should be /a/b/c/3, but the child selectors only
+ // operate on the first component after the interest name; in this case, "b"
+ }
}