Performing paginated REST API searches on Crowd with PostgreSQL linguistic collations results in duplicated and missing data compared to single-page requests

XMLWordPrintable

    • Type: Bug
    • Resolution: Unresolved
    • Priority: Medium
    • None
    • Affects Version/s: 7.2.1, 7.2.2
    • Component/s: Database, Directories, REST
    • None
    • 1
    • Severity 1 - Critical
    • 7

      Issue Summary

      Performing paginated REST API searches on Crowd with PostgreSQL linguistic collations results in duplicated and missing data compared to single-page requests.

      Steps to Reproduce

      1. Configure a PostgreSQL database with a linguistic collation:

      CREATE DATABASE crowd_enus
        WITH OWNER = crowd
        ENCODING = 'UTF8'
        LC_COLLATE = 'en_US.UTF-8'
        LC_CTYPE = 'en_US.UTF-8'
        LOCALE_PROVIDER = 'libc'
        TEMPLATE = template0; 

      2. Configure a Crowd instance to use this database and complete the initial setup.

      3. Stop Crowd.

      4. Execute the attached SQL script (repro_crowd_pagination.sql) - it creates two internal directories, one application mapped to both, and 1000 groups (group names rotate through five separators: space, hyphen, full stop, underscore, none).

      5. Start Crowd.

      6. Enable "Allow basic authentication on API calls" in Crowd (Configuration > Authentication Methods).

      7. Execute a series of paginated REST API calls to /rest/usermanagement/1/search using start-index and max-results to retrieve all groups.

        for START in 0 100 200 300 400 500 600 700 800 900; do
          curl -sS -u 'reprotest:reprotest123' -H 'Accept: application/json' \
            "http://<crowd-host>:<crowd_port>/crowd/rest/usermanagement/1/search\
      ?entity-type=group&restriction=name%3Dzztest*\
      &start-index=${START}&max-results=100"
        done | jq > output-paginated.txt 

      8. Execute a single REST API call to retrieve the same set of groups in one page (for example, max-results=10000).

        curl -sS -u 'reprotest:reprotest123' -H 'Accept: application/json' \
          "http://<crowd-host>:<crowd_port>/crowd/rest/usermanagement/1/search\
      ?entity-type=group&restriction=name%3Dzztest*\
      &start-index=0&max-results=10000" | jq > output-single-page.txt 

      9. Compare the total number of unique records returned by the paginated calls versus the single-page call.

      % grep -w name output-paginated.txt | sort -u | wc -l
      % grep -w name output-single-page.txt | sort -u | wc -l

      10. For detailed comparison:

      % diff <(grep -w name output-paginated.txt | sort) <(grep -w name output-single-page.txt | sort) 

      Expected Results

      The paginated requests should return the same total number of unique records as the single-page request (for example, 1000 records).

      A detailed comparison of the outputs of both requests should show the same group names.

      Actual Results

      The paginated requests return fewer unique records (for example, 680 records) than the single-page request:

      % grep -w name output-paginated.txt | sort -u | wc -l
          680
      % grep -w name output-single-page.txt | sort -u | wc -l
          1000  

      A detailed comparison of the outputs of both requests indicates that some records are duplicated, while others are skipped or lost during pagination.

      Affected endpoints: 

      API Endpoint Returns
      usermanagement/1 /crowd/rest/usermanagement/1/search?entity-type=user users
      usermanagement/1 /crowd/rest/usermanagement/1/search?entity-type=group groups
      usermanagement/1 /crowd/rest/usermanagement/1/user/group/direct user's direct groups
      usermanagement/1 /crowd/rest/usermanagement/1/user/group/nested user's nested groups
      usermanagement/1 /crowd/rest/usermanagement/1/group/user/direct group's direct users
      usermanagement/1 /crowd/rest/usermanagement/1/group/user/nested group's nested users
      usermanagement/1 /crowd/rest/usermanagement/1/group/parent-group/direct group's direct parent groups
      usermanagement/1 /crowd/rest/usermanagement/1/group/parent-group/nested group's nested parent groups
      usermanagement/1 /crowd/rest/usermanagement/1/group/child-group/direct group's direct child groups
      usermanagement/1 /crowd/rest/usermanagement/1/group/child-group/nested group's nested child groups
      admin/1.0 /crowd/rest/admin/1.0/users/search users
      admin/1.0 /crowd/rest/admin/1.0/<groupId>/admins/suggestions users/groups (admin candidates)

      Workaround

      • Use a single REST API call with max-results higher than the total number of entities to retrieve the same set of entities in one page. The limit is memory, not a fixed cap — the whole result set is built and re-sorted in server memory (then sent to the client), so only use result sets that comfortably fit in the heap. Memory use can be a problem for large data sets.
      • Use a PostgreSQL database configured with the C collation. For example:
      CREATE DATABASE crowd_c
      WITH OWNER = crowd
      ENCODING 'UTF8'
      LOCALE_PROVIDER builtin
      BUILTIN_LOCALE 'C.UTF-8'
      TEMPLATE template0; 

        1. repro_crowd_pagination.sql
          7 kB
          Gabriel Piedade

              Assignee:
              Unassigned
              Reporter:
              Gabriel Piedade
              Votes:
              0 Vote for this issue
              Watchers:
              1 Start watching this issue

                Created:
                Updated: