jackrabbit-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "David Rauschenbach" <david.rauschenb...@synchronica.com>
Subject Re: SPI caching, was: [jira] Resolved: (JCR-1361) Lock testassumes that changes in one session are immediately visible in differentsession
Date Tue, 12 Feb 2008 11:51:53 GMT
 
Some other SPI deficiencies off the top of my head, while we're on the
subject:

  1. Default workspace name. They should not be specified in JCR2SPI.
When you log into Exchange or an IMAP server, or a SQL Server, you get a
default namespace (or database) based on what the server thinks is the
right default name for you. The name should not be known at the client
(that's why it's a default!). Once you're logged in, you can ask for
other namespace names, which also fits in nicely with JCR
(Workspace.getAccessibleWorkspaceNames). But specifying a default
namespace name in JCR2SPI is wrong, because a null should be passed when
the server should choose.

  2. Repository descriptors over SPI. This is a deficiency. I have a web
service that remotes SPI, and I can't ask the target web service for the
repository descriptors. It doesn't help that JCR2SPI asks for the
descriptors before a login. That makes it almost mandatory to mock up
fake values in the SPI, before a dynamic proxy can initialize itself, if
initialization is dependent on logging in, as is the case in 2 out of
the 5 SPIs I have in front of me, or in cases where the target web
service is deployed under the umbrella of container-managed security.

  3. Out-of-band data. Since JCR doesn't address configuration, or a
RepositoryFactory pattern (even though Jackrabbit provides one), it is
up to each implementation to get configuration done. SPI could use a
place to pass this data. SimpleCredential attributes are not enough.
IIOP for CORBA is a good example, where you can stuff profiles with your
extra data, like timezone of the client, alternate server names,
whatever. For SPI, the out-of-band data could be a place where the
implementation-specific BatchReadConfig for a specific getItemInfos
operation could be placed. I'm not sure this is a good idea for SPI, but
I'm thinking about it.

David



On Mon, 2008-02-11 at 18:49 +0100, Julian Reschke wrote:
> Julian Reschke wrote:
> > At the end of the day, what we should do is *measure* the performance of 
> > JCR2SPI compared to native implementations. I'll try to submit a few 
> > tests soon.
> > ...
> 
> OK, I've got tests (not polished) and numbers.
> 
> Scenario:
> 
> A collection /a/b with 500 members, each 1024 in size, content type 
> application/octet-stream.
> 
> Test code that obtains all members, checking content type, size, and 
> total number.
> 
> My store can do that in ~80ms.
> 
> Why doing it through SPI (with limited batch read support), it will take 
> ~1500ms.
> 
> Wrapping that with JCR2SPI, it takes around ~2700ms.
> 
> So it seems we need drastically remove the overhead introduced by the 
> SPI API.
> 
> Test code below:
> 
> 
>    private String createTestCollJcr(String p_parentpath, int p_members, 
> int p_size) throws Exception {
>      Repository l_repository = getRepository();
>      Session l_session = null;
> 
>      try {
>        l_session = l_repository.login(getCredentials());
> 
>        Node l_folder = null;
>        try {
>          l_folder = (Node)l_session.getItem(p_parentpath + "/bigcoll");
>        }
>        catch (RepositoryException ex) {
>          // nothing to do
>        }
> 
>        // delete when needed
>        if (l_folder != null) {
>          l_folder.remove();
>          l_session.save();
>        }
> 
>        Node l_parent = (Node)l_session.getItem(p_parentpath);
>        l_folder = l_parent.addNode("bigcoll", "nt:folder");
>        assertNotNull(l_folder);
> 
>        long l_cnt = 0;
> 
>        while (l_cnt < p_members) {
>          InputStream l_is = new BufferedInputStream(new 
> ContentGenerator(p_size), p_size);
>          Node l_new = l_folder.addNode("tst" + l_cnt, "nt:file");
>          Node l_cnew = l_new.addNode("jcr:content", "nt:resource");
>          l_cnew.setProperty("jcr:data", l_is);
>          l_cnew.setProperty("jcr:mimeType", "application/octet-stream");
>          l_session.save();
>          l_cnt += 1;
>        }
>      }
>      finally {
>        if (l_session != null) {
>          l_session.logout();
>        }
>      }
> 
>      return p_parentpath + "/bigcoll";
>    }
> 
> 
>    private static int BIGCOLLMEMBERS = 500;
>    private static int BIGCOLLMEMBERSIZE = 1024;
>    private static String BIGCOLLMIMETYPE = "application/octet-stream";
> 
>    public void testGetMembersSpi() throws Exception {
> 
>      String l_path = createTestColl(this.m_path, BIGCOLLMEMBERS, 
> BIGCOLLMEMBERSIZE);
> 
>      RepositoryService l_rs = getRepositoryService();
>      SessionInfo l_si = null;
> 
>      try {
>        l_si = l_rs.obtain(getCredentials(), null);
> 
>        long l_start = System.currentTimeMillis();
>        long l_cnt = 0;
> 
>        while (System.currentTimeMillis() - l_start < MS || l_cnt < 5) {
>          NodeId l_nid = TestPerf.computeNodeId(l_rs, l_si, l_path);
>          int l_members = 0;
>          for (Iterator<ChildInfo> l_it = 
> (Iterator<ChildInfo>)l_rs.getChildInfos(l_si, l_nid); l_it.hasNext(); ) {
>            ChildInfo l_c = l_it.next();
>            assertNotNull(l_c);
>            NodeId l_cnid = 
> l_rs.getIdFactory().createNodeId(l_c.getUniqueID());
>            NodeInfo l_node = null;
>            NodeInfo l_contentnode = null;
>            PropertyInfo l_mimetype = null;
>            PropertyInfo l_data = null;
>            Iterator l_iteminfos = l_rs.getItemInfos(l_si, l_cnid);
>            l_node = (NodeInfo)l_iteminfos.next();
>            assertNotNull(l_node);
> 
>            while (l_iteminfos.hasNext()) {
>              ItemInfo l_i = (ItemInfo)l_iteminfos.next();
>              if (l_i.getParentId().equals(l_node.getId()) && 
> NameConstants.JCR_CONTENT.equals(l_i.getName())) {
>                l_contentnode = (NodeInfo)l_i;
>              }
>              if (l_contentnode != null && 
> l_i.getParentId().equals(l_contentnode.getId()) && 
> NameConstants.JCR_MIMETYPE.equals(l_i.getName())) {
>                l_mimetype = (PropertyInfo)l_i;
>              }
>              if (l_contentnode != null && 
> l_i.getParentId().equals(l_contentnode.getId()) && 
> NameConstants.JCR_DATA.equals(l_i.getName())) {
>                l_data = (PropertyInfo)l_i;
>              }
>            }
> 
>            if (l_contentnode == null) {
>              // explicitly fetch the content node, it wasn't returned 
> with the parent
>              NodeId l_contentnodeid = 
> l_rs.getIdFactory().createNodeId(l_c.getUniqueID(), 
> l_rs.getPathFactory().create(NameConstants.JCR_CONTENT));
>              Iterator l_iteminfos2 = l_rs.getItemInfos(l_si, 
> l_contentnodeid);
>              l_contentnode = (NodeInfo)l_iteminfos2.next();
>              while (l_iteminfos2.hasNext()) {
>                ItemInfo l_i = (ItemInfo)l_iteminfos2.next();
>                if (l_i.getParentId().equals(l_contentnode.getId()) && 
> NameConstants.JCR_MIMETYPE.equals(l_i.getName())) {
>                  l_mimetype = (PropertyInfo)l_i;
>                }
>                if (l_i.getParentId().equals(l_contentnode.getId()) && 
> NameConstants.JCR_DATA.equals(l_i.getName())) {
>                  l_data = (PropertyInfo)l_i;
>                }
>              }
>            }
> 
>            assertNotNull(l_contentnode);
> 
>            if (l_mimetype == null) {
>              // explicitly fetch the mime type property, it wasn't 
> returned with the parent
>              PropertyId l_mimetypeid = 
> l_rs.getIdFactory().createPropertyId(l_contentnode.getId(), 
> NameConstants.JCR_MIMETYPE);
>              l_mimetype = l_rs.getPropertyInfo(l_si, l_mimetypeid);
>            }
> 
>            assertNotNull(l_mimetype);
>            assertEquals(BIGCOLLMIMETYPE, 
> l_mimetype.getValues()[0].getString());
> 
>            if (l_data == null) {
>              // explicitly fetch the mime type property, it wasn't 
> returned with the parent
>              PropertyId l_dataid = 
> l_rs.getIdFactory().createPropertyId(l_contentnode.getId(), 
> NameConstants.JCR_DATA);
>              l_data = l_rs.getPropertyInfo(l_si, l_dataid);
>            }
> 
>            assertNotNull(l_data);
>            assertEquals(BIGCOLLMEMBERSIZE, 
> l_data.getValues()[0].getLength());
> 
>            l_members += 1;
>          }
>          assertEquals(BIGCOLLMEMBERS, l_members);
>          l_cnt += 1;
>        }
> 
>        long l_elapsed = System.currentTimeMillis() - l_start;
> 
>        LOG.info(String.format("GetMembers - SPI: %.4fms per call (%d 
> iterations)", (double)l_elapsed / l_cnt, l_cnt));
> 
>      }
>      finally {
>        if (l_si != null) {
>          l_rs.dispose(l_si);
>        }
>      }
>    }
> 
>    public void testGetMembersJcr() throws Exception {
> 
>      String l_path = createTestCollJcr(this.m_path, BIGCOLLMEMBERS, 
> BIGCOLLMEMBERSIZE);
> 
>      Repository l_repository = getRepository();
>      Session l_session = null;
> 
>      try {
>        l_session = l_repository.login(getCredentials(), null);
> 
>        long l_start = System.currentTimeMillis();
>        long l_cnt = 0;
> 
>        while (System.currentTimeMillis() - l_start < MS || l_cnt < 5) {
>          Node l_dir = (Node)l_session.getItem(l_path);
>          assertNotNull(l_dir);
>          int l_members = 0;
>          for (NodeIterator l_it = l_dir.getNodes(); l_it.hasNext(); ) {
>            Node l_c = l_it.nextNode();
>            Node l_e = l_c.getNode("jcr:content");
>            String l_type = l_e.getProperty("jcr:mimeType").getString();
>            long l_length = l_e.getProperty("jcr:data").getLength();
>            assertTrue(l_c.isNode());
>            assertEquals(BIGCOLLMIMETYPE, l_type);
>            assertEquals(BIGCOLLMEMBERSIZE, l_length);
>            l_members += 1;
>          }
>          assertEquals(BIGCOLLMEMBERS, l_members);
>          l_session.refresh(false);
>          l_cnt += 1;
>        }
> 
>        long l_elapsed = System.currentTimeMillis() - l_start;
> 
>        LOG.info(String.format("GetMembers - JCR: %.4fms per call (%d 
> iterations)", (double)l_elapsed / l_cnt, l_cnt));
> 
>      }
>      finally {
>        if (l_session != null) {
>          l_session.logout();
>        }
>      }
>    }
> 
>    private class ContentGenerator extends InputStream {
> 
>      private long m_length;
>      private long m_position;
> 
>      public ContentGenerator(long p_length) {
>        this.m_length = p_length;
>        this.m_position = 0;
>      }
> 
>      public int read() {
> 
>        if (this.m_position++ < this.m_length) {
>          return 0;
>        }
>        else {
>          return -1;
>        }
>      }
>    }
> 

 
Visit Synchronica at GSMA Mobile World Congress, Barcelona, 11-14 Feb, Hall 2, Booth #2J25
 
 

Mime
View raw message