Uploaded image for project: 'Confluence Data Center'
  1. Confluence Data Center
  2. CONFSERVER-59747

Publishing a page with a large table might be slow if Collaborative Editing is enabled on Confluence

    XMLWordPrintable

Details

    Description

      Issue Summary

      Updating a page with a large table might be slow on Confluence if Collaborative Editing is enabled.
      This causes frustrated users since sometimes it may take dozens of seconds to save a visually simple page.

      Steps to Reproduce

      1. Install a vanilla instance of Confluence.
        • This was validated on Confluence Server 6.13.10 and 7.3.3.
      2. Make sure Collaborative Editing is enabled.
      3. Create a sample Space.
      4. Create a sample Page and publish it.
      5. Edit the recently created page, make any simple change to the content and publish it.
        • You will notice the page is saved pretty quick.
        • Monitoring the browser requests from the developer tools shows a quick response on the PUT request to <Confluence Base URL>/rest/api/content/<pageID>?status=draft.
      6. Edit the page again, create a table with 30 columns and 100 rows and publish the new version.
        • You will notice the page takes more time to be saved.
        • Monitoring the browser requests from the developer tools shows an increase on the response time related to the PUT request to <Confluence Base URL>/rest/api/content/<pageID>?status=draft.
      7. Edit the page again, add 30 more rows to the table and publish the page (you may use the attached sample storage format).
        • You will notice the page takes more time to be saved.
        • Monitoring the browser requests from the developer tools shows an increase on the response time related to the PUT request to <Confluence Base URL>/rest/api/content/<pageID>?status=draft.
      8. Create a new sample Page and publish it.
      9. Edit this page, add plain text content worth of ~700KB (you may use the attached sample storage format) and publish the page.
        • You will notice the page is saved pretty quick, although there's an increase it isn't as high as it was with the table, although the size of the transferred content is about the same.
        • Monitoring the browser requests from the developer tools shows a quick response on the PUT request to <Confluence Base URL>/rest/api/content/<pageID>?status=draft.
      10. Disable Collaborative Editing.
      11. Go to the same page with the large table.
      12. Edit the page, adding a few lines of plain text and publish the page.
        • The page is saved pretty fast, taking around the same time as the plain text page.
        • Monitoring the browser requests from the developer tools shows a quick response on the PUT request to <Confluence Base URL>/rest/api/content/<pageID>?status=current.

      Expected Results

      Saving a page with a complex table is quickly processed by Confluence whether Collaborative Editing is enabled or not.

      Actual Results

      Saving a page with a complex table takes more time than what happens with plain text pages about the size.
      Disabling Collaborative Editing takes less time, showing there's additional complexity on processing the request when Synchrony is in the play.

      If we take thread dumps while the PUT request is being processed, threads with stack traces similar to the below may appear.
      Confluence:

      "http-nio-21310-exec-8 url:/c61310/rest/api/content/3932164 username:admin" #202 daemon prio=5 os_prio=31 tid=0x00007f8758606000 nid=0x1ce03 runnable [0x0000700020b0b000]
         java.lang.Thread.State: RUNNABLE
      	at java.net.SocketInputStream.socketRead0(Native Method)
      	at java.net.SocketInputStream.socketRead(SocketInputStream.java:116)
      	at java.net.SocketInputStream.read(SocketInputStream.java:171)
      	at java.net.SocketInputStream.read(SocketInputStream.java:141)
      	at org.apache.http.impl.io.SessionInputBufferImpl.streamRead(SessionInputBufferImpl.java:137)
      	at org.apache.http.impl.io.SessionInputBufferImpl.fillBuffer(SessionInputBufferImpl.java:153)
      	at org.apache.http.impl.io.SessionInputBufferImpl.readLine(SessionInputBufferImpl.java:282)
      	at org.apache.http.impl.conn.DefaultHttpResponseParser.parseHead(DefaultHttpResponseParser.java:138)
      	at org.apache.http.impl.conn.DefaultHttpResponseParser.parseHead(DefaultHttpResponseParser.java:56)
      	at org.apache.http.impl.io.AbstractMessageParser.parse(AbstractMessageParser.java:259)
      	at org.apache.http.impl.DefaultBHttpClientConnection.receiveResponseHeader(DefaultBHttpClientConnection.java:163)
      	at org.apache.http.impl.conn.CPoolProxy.receiveResponseHeader(CPoolProxy.java:165)
      	at org.apache.http.protocol.HttpRequestExecutor.doReceiveResponse(HttpRequestExecutor.java:273)
      	at org.apache.http.protocol.HttpRequestExecutor.execute(HttpRequestExecutor.java:125)
      	at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:272)
      	at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:185)
      	at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:89)
      	at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:111)
      	at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:185)
      	at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:72)
      	at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:221)
      	at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:165)
      	at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:140)
      	at com.atlassian.confluence.plugins.synchrony.service.http.SynchronyRequestExecutor.execute(SynchronyRequestExecutor.java:43)
      	at com.atlassian.confluence.plugins.synchrony.service.SynchronyAbstractManager.execute(SynchronyAbstractManager.java:72)
      	at com.atlassian.confluence.plugins.synchrony.service.SynchronyExternalChangesManager.performExternalChange(SynchronyExternalChangesManager.java:76)
      	at com.atlassian.confluence.plugins.synchrony.service.SynchronyExternalChangesManager.syncContentOnUpdate(SynchronyExternalChangesManager.java:64)
      	at com.atlassian.confluence.plugins.synchrony.service.SynchronyContentService.syncContentOnUpdate(SynchronyContentService.java:111)
      	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
      	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
      	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
      	at java.lang.reflect.Method.invoke(Method.java:498)
      (...)
      	at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
      	- locked <0x000000077bb81e00> (a org.apache.tomcat.util.net.NioEndpoint$NioSocketWrapper)
      	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
      	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
      	at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
      	at java.lang.Thread.run(Thread.java:748)
      

      Synchrony:

      "async-dispatch-8" #29 daemon prio=5 os_prio=31 tid=0x00007fe9799eb000 nid=0x6303 runnable [0x0000700007a3a000]
         java.lang.Thread.State: RUNNABLE
      	at clojure.lang.Reflector.getInstanceField(Reflector.java:259)
      	at clojure.lang.Reflector.invokeNoArgInstanceMember(Reflector.java:306)
      	at synchrony.operation.diff$edit_type.invokeStatic(diff.cljc:97)
      	at synchrony.operation.diff$edit_type.invoke(diff.cljc:95)
      	at synchrony.operation.diff$in_sequence_QMARK_.invokeStatic(diff.cljc:313)
      	at synchrony.operation.diff$in_sequence_QMARK_.invoke(diff.cljc:312)
      	at synchrony.operation.diff$match_edit_trees.invokeStatic(diff.cljc:485)
      	at synchrony.operation.diff$match_edit_trees.invoke(diff.cljc:410)
      	at synchrony.operation.diff$zip_edit_trees.invokeStatic(diff.cljc:611)
      	at synchrony.operation.diff$zip_edit_trees.invoke(diff.cljc:609)
      	at synchrony.operation.diff$diff_trees.invokeStatic(diff.cljc:684)
      	at synchrony.operation.diff$diff_trees.invoke(diff.cljc:643)
      	at synchrony.data.content_reconciliation$process_revision_info$fn__47662$state_machine__5591__auto____47663$fn__47665.invoke(content_reconciliation.clj:110)
      	at synchrony.data.content_reconciliation$process_revision_info$fn__47662$state_machine__5591__auto____47663.invoke(content_reconciliation.clj:110)
      	at clojure.core.async.impl.ioc_macros$run_state_machine.invokeStatic(ioc_macros.clj:1012)
      	at clojure.core.async.impl.ioc_macros$run_state_machine.invoke(ioc_macros.clj:1011)
      	at clojure.core.async.impl.ioc_macros$run_state_machine_wrapped.invokeStatic(ioc_macros.clj:1016)
      	at clojure.core.async.impl.ioc_macros$run_state_machine_wrapped.invoke(ioc_macros.clj:1014)
      	at clojure.core.async.impl.ioc_macros$take_BANG_$fn__5609.invoke(ioc_macros.clj:1025)
      	at clojure.core.async.impl.channels.ManyToManyChannel$fn__811$fn__812.invoke(channels.clj:95)
      	at clojure.lang.AFn.run(AFn.java:22)
      	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
      	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
      	at java.lang.Thread.run(Thread.java:748)
      

      Workaround

      Currently there is no known workaround for this behavior. A workaround will be added here when available.

      Attachments

        1. har-img-001.png
          har-img-001.png
          270 kB
        2. har-img-002.png
          har-img-002.png
          303 kB
        3. har-img-003.png
          har-img-003.png
          308 kB
        4. har-img-004.png
          har-img-004.png
          306 kB
        5. har-img-006png.png
          har-img-006png.png
          307 kB
        6. har-img-007png.png
          har-img-007png.png
          311 kB
        7. sample-page-plain-text-storageformat.txt
          710 kB
        8. sample-page-with-large-table-storageformat.txt
          697 kB

        Issue Links

          Activity

            People

              Unassigned Unassigned
              tmasutti Thiago Masutti
              Votes:
              52 Vote for this issue
              Watchers:
              46 Start watching this issue

              Dates

                Created:
                Updated: