Cassandra
  1. Cassandra
  2. CASSANDRA-767

Row keys should be byte[]s, not Strings

    Details

      Description

      This issue has come up numerous times, and we've dealt with a lot of pain because of it: let's get it knocked out.

      Keys being Java Strings can make it painful to use Cassandra from other languages, encoding binary data like integers as Strings is very inefficient, and there is a disconnect between our column data types and the plain String treatment we give row keys.

      The key design decision that needs discussion is: Should we apply the column AbstractTypes to row keys? If so, how do Partitioners change?

        Issue Links

        There are no Sub-Tasks for this issue.

          Activity

          Gavin made changes -
          Link This issue depends upon CASSANDRA-389 [ CASSANDRA-389 ]
          Gavin made changes -
          Link This issue depends on CASSANDRA-389 [ CASSANDRA-389 ]
          Gavin made changes -
          Workflow patch-available, re-open possible [ 12752101 ] reopen-resolved, no closed status, patch-avail, testing [ 12758125 ]
          Gavin made changes -
          Workflow no-reopen-closed, patch-avail [ 12498101 ] patch-available, re-open possible [ 12752101 ]
          Hide
          Uwe Schindler added a comment - - edited

          About Lucandra: Currently all keys in Lucene are valid UTF-8 encoded bytes, so making them Strings in Cassandra is fine - also for numeric terms as Todd Nine said (they use only 7 bits of the byte[], so are valid UTF-8 - but there was still a bug in Cassandra by trimming keys, now solved).

          Lucene trunk now has migrated to pure byte[] terms, so Lucandra will do the same. It is therefore no longer guaranteed that terms in an Lucene index are really representable as String, also the ordering of keys must be native unsigned byte[] and not UTF-16 (String.compareTo()) for several Queries in Lucene to work correct.

          Additionally, the encoding of string-type terms in Lucene trunk (aka 4.0) will also change to BOCU-1 for better space efficiency of eastern languages, also numeric terms will saved as raw byte[] with full 8bits, too.

          Show
          Uwe Schindler added a comment - - edited About Lucandra: Currently all keys in Lucene are valid UTF-8 encoded bytes, so making them Strings in Cassandra is fine - also for numeric terms as Todd Nine said (they use only 7 bits of the byte[], so are valid UTF-8 - but there was still a bug in Cassandra by trimming keys, now solved). Lucene trunk now has migrated to pure byte[] terms, so Lucandra will do the same. It is therefore no longer guaranteed that terms in an Lucene index are really representable as String, also the ordering of keys must be native unsigned byte[] and not UTF-16 (String.compareTo()) for several Queries in Lucene to work correct. Additionally, the encoding of string-type terms in Lucene trunk (aka 4.0) will also change to BOCU-1 for better space efficiency of eastern languages, also numeric terms will saved as raw byte[] with full 8bits, too.
          Hide
          Todd Nine added a comment -

          Hey guys. I would like to link this issue as it relates to Stu Hood's previous comments that bytes will be returned as encoded UTF-8 bytes, with the client not caring what data is encoded within those bytes.

          We're tried to do this specifically with Lucandra and numeric range queries. Unfortunately there appears to be a bug in the thrift system. I've created a test case which demonstrates this bug here. It's marked for getting fixed in 6.4, but I want to make sure it's linked to this issue given that it will block clients such as my own from using bytes and could potentially cause problems with migrating to this system in 0.7

          Show
          Todd Nine added a comment - Hey guys. I would like to link this issue as it relates to Stu Hood's previous comments that bytes will be returned as encoded UTF-8 bytes, with the client not caring what data is encoded within those bytes. We're tried to do this specifically with Lucandra and numeric range queries. Unfortunately there appears to be a bug in the thrift system. I've created a test case which demonstrates this bug here. It's marked for getting fixed in 6.4, but I want to make sure it's linked to this issue given that it will block clients such as my own from using bytes and could potentially cause problems with migrating to this system in 0.7
          Todd Nine made changes -
          Link This issue is blocked by CASSANDRA-1235 [ CASSANDRA-1235 ]
          Hide
          Hudson added a comment -

          Integrated in Cassandra #407 (See http://hudson.zones.apache.org/hudson/job/Cassandra/407/)
          import and dead-code cleanup. Patch by Stu Hood, reviewed by Gary Dusbabek. CASSANDRA-767
          use hex keys in sstable import/export. Patch by Stu Hood, reviewed by Gary Dusbabek. CASSANDRA-767
          add ByteOrderedPartitioner. Patch by Stu Hood, reviewed by Gary Dusbabek. CASSANDRA-767
          convert thrift to byte keys. Patch by Stu Hood, reviewed by Gary Dusbabek. CASSANDRA-767
          byte for decorateKey and getToken in IPartitioner. Patch by Stu Hood, reviewed by Gary Dusbabek. CASSANDRA-767
          bump sstable version to c. remove utf-16 encoding. Patch by Stu Hood, reviewed by Gary Dusbabek. CASSANDRA-767
          convert IPartitioner disk key format to bytes. Patch by Stu Hood, reviewed by Gary Dusbabek. CASSANDRA-767
          extract read/write-Name. Patch by Stu Hood, reviewed by Gary Dusbabek. CASSANDRA-767
          store bytes in DecoratedKey. Patch by Stu Hood, reviewed by Gary Dusbabek. CASSANDRA-767
          implement a legacy sstable test. Patch by Stu Hood, reviewed by Gary Dusbabek. CASSANDRA-767
          increase test ram. Patch by Stu Hood, reviewed by Gary Dusbabek. CASSANDRA-767
          implement a compaction benchmark. Patch by Stu Hood, reviewed by Gary Dusbabek. CASSANDRA-767

          Show
          Hudson added a comment - Integrated in Cassandra #407 (See http://hudson.zones.apache.org/hudson/job/Cassandra/407/ ) import and dead-code cleanup. Patch by Stu Hood, reviewed by Gary Dusbabek. CASSANDRA-767 use hex keys in sstable import/export. Patch by Stu Hood, reviewed by Gary Dusbabek. CASSANDRA-767 add ByteOrderedPartitioner. Patch by Stu Hood, reviewed by Gary Dusbabek. CASSANDRA-767 convert thrift to byte keys. Patch by Stu Hood, reviewed by Gary Dusbabek. CASSANDRA-767 byte for decorateKey and getToken in IPartitioner. Patch by Stu Hood, reviewed by Gary Dusbabek. CASSANDRA-767 bump sstable version to c. remove utf-16 encoding. Patch by Stu Hood, reviewed by Gary Dusbabek. CASSANDRA-767 convert IPartitioner disk key format to bytes. Patch by Stu Hood, reviewed by Gary Dusbabek. CASSANDRA-767 extract read/write-Name. Patch by Stu Hood, reviewed by Gary Dusbabek. CASSANDRA-767 store bytes in DecoratedKey. Patch by Stu Hood, reviewed by Gary Dusbabek. CASSANDRA-767 implement a legacy sstable test. Patch by Stu Hood, reviewed by Gary Dusbabek. CASSANDRA-767 increase test ram. Patch by Stu Hood, reviewed by Gary Dusbabek. CASSANDRA-767 implement a compaction benchmark. Patch by Stu Hood, reviewed by Gary Dusbabek. CASSANDRA-767
          Gary Dusbabek made changes -
          Status Patch Available [ 10002 ] Resolved [ 5 ]
          Resolution Fixed [ 1 ]
          Hide
          Gary Dusbabek added a comment -

          Committed with minor modifications. Thanks Stu!

          Show
          Gary Dusbabek added a comment - Committed with minor modifications. Thanks Stu!
          Hide
          Stu Hood added a comment -

          0006 Now fully removes String support from Filter.

          Sorry for the mixup: luckily one of our platforms was encoding Strings differently to expose this.

          Show
          Stu Hood added a comment - 0006 Now fully removes String support from Filter. Sorry for the mixup: luckily one of our platforms was encoding Strings differently to expose this.
          Stu Hood made changes -
          Stu Hood made changes -
          Attachment 0001-Implement-compaction-benchmark.patch [ 12441553 ]
          Stu Hood made changes -
          Attachment 0002-Implement-a-legacy-sstable-test.patch [ 12441554 ]
          Stu Hood made changes -
          Attachment 0003-Store-bytes-in-DecoratedKey-and-cleanup-dead-code.patch [ 12441555 ]
          Stu Hood made changes -
          Attachment 0004-Extract-read-writeName.patch [ 12441556 ]
          Stu Hood made changes -
          Attachment 0005-Convert-IPartitioner-disk-key-format-to-bytes.patch [ 12441557 ]
          Stu Hood made changes -
          Attachment 0006-Bump-SSTable-version-to-c-remove-utf16-encoding-from.patch [ 12441558 ]
          Hide
          Gary Dusbabek added a comment -

          I get a test failure 100% of the time after applying these patches:

          [junit] Testcase: testFalsePositivesRandom(org.apache.cassandra.utils.BloomFilterTest): FAILED
          [junit] 10.280434782608696
          [junit] junit.framework.AssertionFailedError: 10.280434782608696
          [junit] at org.apache.cassandra.utils.FilterTest.testFalsePositives(FilterTest.java:97)
          [junit] at org.apache.cassandra.utils.BloomFilterTest.testFalsePositivesRandom(BloomFilterTest.java:71)
          [junit]

          Show
          Gary Dusbabek added a comment - I get a test failure 100% of the time after applying these patches: [junit] Testcase: testFalsePositivesRandom(org.apache.cassandra.utils.BloomFilterTest): FAILED [junit] 10.280434782608696 [junit] junit.framework.AssertionFailedError: 10.280434782608696 [junit] at org.apache.cassandra.utils.FilterTest.testFalsePositives(FilterTest.java:97) [junit] at org.apache.cassandra.utils.BloomFilterTest.testFalsePositivesRandom(BloomFilterTest.java:71) [junit]
          Hide
          Stu Hood added a comment -

          Rebased for trunk. Thanks for your patience!

          Show
          Stu Hood added a comment - Rebased for trunk. Thanks for your patience!
          Stu Hood made changes -
          Attachment 0004-Extract-read-writeName.patch [ 12441556 ]
          Attachment 0005-Convert-IPartitioner-disk-key-format-to-bytes.patch [ 12441557 ]
          Attachment 0006-Bump-SSTable-version-to-c-remove-utf16-encoding-from.patch [ 12441558 ]
          Stu Hood made changes -
          Attachment 0001-Implement-compaction-benchmark.patch [ 12441553 ]
          Attachment 0002-Implement-a-legacy-sstable-test.patch [ 12441554 ]
          Attachment 0003-Store-bytes-in-DecoratedKey-and-cleanup-dead-code.patch [ 12441555 ]
          Stu Hood made changes -
          Attachment 0006-Bump-SSTable-version-to-c-remove-utf16-encoding-from.patch [ 12440766 ]
          Stu Hood made changes -
          Attachment 0005-Convert-IPartitioner-disk-key-format-to-bytes.patch [ 12440933 ]
          Stu Hood made changes -
          Attachment 0004-Extract-read-writeName.patch [ 12440764 ]
          Stu Hood made changes -
          Attachment 0003-Store-bytes-in-DecoratedKey-and-cleanup-dead-code.patch [ 12440763 ]
          Stu Hood made changes -
          Attachment 0002-Implement-a-legacy-sstable-test.patch [ 12440762 ]
          Stu Hood made changes -
          Attachment 0001-Implement-compaction-benchmark.patch [ 12440761 ]
          Stu Hood made changes -
          Attachment 0005-Convert-IPartitioner-disk-key-format-to-bytes.patch [ 12440933 ]
          Hide
          Stu Hood added a comment -

          Updated 0005 to remove DELIMITER.

          Show
          Stu Hood added a comment - Updated 0005 to remove DELIMITER.
          Stu Hood made changes -
          Attachment 0005-Convert-IPartitioner-disk-key-format-to-bytes.patch [ 12440788 ]
          Hide
          Gary Dusbabek added a comment -

          > RandomPartitioner: it wouldn't take a lot of work to get rid of DELIMITER.
          I was referring to DELIMITER the string constant, not the concept of using a byte delimiter. It's only used in convertFromDiskFormat.

          Show
          Gary Dusbabek added a comment - > RandomPartitioner: it wouldn't take a lot of work to get rid of DELIMITER. I was referring to DELIMITER the string constant, not the concept of using a byte delimiter. It's only used in convertFromDiskFormat.
          Stu Hood made changes -
          Status Open [ 1 ] Patch Available [ 10002 ]
          Stu Hood made changes -
          Attachment 0005-Convert-IPartitioner-disk-key-format-to-bytes.patch [ 12440788 ]
          Hide
          Stu Hood added a comment -

          > FBUtilities: got rid of readNullableString, but not writeNullableString. It looks like mapToString is unused as well.
          Attaching a new copy of 0005 that kills those as well.

          > Filters: I think there is still some more work that can be done here to get rid of string-keys
          This is coming in 953... unfortunately, I underestimated how large it would get, but I think I've kept it relatively compartmentalized.

          > RandomPartitioner: it wouldn't take a lot of work to get rid of DELIMITER.
          Yes, but it would require conditional behaviour in RandomPartitioner.convert* based on the SSTable version, which isn't fun. I'd prefer to do that in another patch if possible: perhaps one that removes the 'convertToDisk' methods entirely.

          > When CASSANDRA-953 is done, we'll not have string keys anywhere, right?
          Correct: it's a larger patchset than I expected, but it is almost finished.

          Show
          Stu Hood added a comment - > FBUtilities: got rid of readNullableString, but not writeNullableString. It looks like mapToString is unused as well. Attaching a new copy of 0005 that kills those as well. > Filters: I think there is still some more work that can be done here to get rid of string-keys This is coming in 953... unfortunately, I underestimated how large it would get, but I think I've kept it relatively compartmentalized. > RandomPartitioner: it wouldn't take a lot of work to get rid of DELIMITER. Yes, but it would require conditional behaviour in RandomPartitioner.convert* based on the SSTable version, which isn't fun. I'd prefer to do that in another patch if possible: perhaps one that removes the 'convertToDisk' methods entirely. > When CASSANDRA-953 is done, we'll not have string keys anywhere, right? Correct: it's a larger patchset than I expected, but it is almost finished.
          Stu Hood made changes -
          Attachment 0005-Convert-IPartitioner-disk-key-format-to-bytes.patch [ 12440765 ]
          Hide
          Gary Dusbabek added a comment -

          Looking good. A few minor things:

          FBUtilities: got rid of readNullableString, but not writeNullableString. It looks like mapToString is unused as well.
          Filters: I think there is still some more work that can be done here to get rid of string-keys (get rid of getHashBuckets and rework filter tests so that they iterate through byte[] and not String for keys).
          RandomPartitioner: it wouldn't take a lot of work to get rid of DELIMITER.

          When CASSANDRA-953 is done, we'll not have string keys anywhere, right? That includes RowMutation, DecoratedKey, storage APIs, the works?

          Show
          Gary Dusbabek added a comment - Looking good. A few minor things: FBUtilities: got rid of readNullableString, but not writeNullableString. It looks like mapToString is unused as well. Filters: I think there is still some more work that can be done here to get rid of string-keys (get rid of getHashBuckets and rework filter tests so that they iterate through byte[] and not String for keys). RandomPartitioner: it wouldn't take a lot of work to get rid of DELIMITER. When CASSANDRA-953 is done, we'll not have string keys anywhere, right? That includes RowMutation, DecoratedKey, storage APIs, the works?
          Stu Hood made changes -
          Attachment 0004-Extract-read-writeName.patch [ 12440764 ]
          Attachment 0005-Convert-IPartitioner-disk-key-format-to-bytes.patch [ 12440765 ]
          Attachment 0006-Bump-SSTable-version-to-c-remove-utf16-encoding-from.patch [ 12440766 ]
          Hide
          Stu Hood added a comment -

          Rebased for trunk.

          Show
          Stu Hood added a comment - Rebased for trunk.
          Stu Hood made changes -
          Attachment 0001-Implement-compaction-benchmark.patch [ 12440761 ]
          Attachment 0002-Implement-a-legacy-sstable-test.patch [ 12440762 ]
          Attachment 0003-Store-bytes-in-DecoratedKey-and-cleanup-dead-code.patch [ 12440763 ]
          Stu Hood made changes -
          Attachment 0006-Bump-SSTable-version-to-c-remove-utf16-encoding-from.patch [ 12440595 ]
          Stu Hood made changes -
          Attachment 0005-Convert-IPartitioner-disk-key-format-to-bytes.patch [ 12440594 ]
          Stu Hood made changes -
          Attachment 0004-Extract-read-writeName.patch [ 12440593 ]
          Stu Hood made changes -
          Attachment 0003-Store-bytes-in-DecoratedKey-and-cleanup-dead-code.patch [ 12440591 ]
          Stu Hood made changes -
          Attachment 0002-Implement-a-legacy-sstable-test.patch [ 12440590 ]
          Stu Hood made changes -
          Attachment 0001-Implement-compaction-benchmark.patch [ 12440589 ]
          Stu Hood made changes -
          Attachment 0004-Extract-read-writeName.patch [ 12440593 ]
          Attachment 0005-Convert-IPartitioner-disk-key-format-to-bytes.patch [ 12440594 ]
          Attachment 0006-Bump-SSTable-version-to-c-remove-utf16-encoding-from.patch [ 12440595 ]
          Hide
          Stu Hood added a comment -

          Implements the first half of the byte-keys refactor:

          1. uses bytes internally in DecoratedKey
          2. modifies IPartitioners to use bytes on disk
          3. removes requirement for utf16 data in bloomfilters (sstable version bump to 'c')

          These patches don't yet touch TokenFactory or the Thrift/Avro interfaces at all. Some of the remaining steps include:

          1. removing String creation for DecoratedKeys
          2. converting TokenFactory to bytes
          3. modifying thrift/avro interfaces
          4. introducing a ByteOrderedPartitioner
          Show
          Stu Hood added a comment - Implements the first half of the byte-keys refactor: uses bytes internally in DecoratedKey modifies IPartitioners to use bytes on disk removes requirement for utf16 data in bloomfilters (sstable version bump to 'c') These patches don't yet touch TokenFactory or the Thrift/Avro interfaces at all. Some of the remaining steps include: removing String creation for DecoratedKeys converting TokenFactory to bytes modifying thrift/avro interfaces introducing a ByteOrderedPartitioner
          Stu Hood made changes -
          Attachment 0001-Implement-compaction-benchmark.patch [ 12440589 ]
          Attachment 0002-Implement-a-legacy-sstable-test.patch [ 12440590 ]
          Attachment 0003-Store-bytes-in-DecoratedKey-and-cleanup-dead-code.patch [ 12440591 ]
          Hide
          Jonathan Ellis added a comment -

          re bloom filter rebuilding, if you do it in the index scan loop it will be a lot faster than scanning the data file.

          Show
          Jonathan Ellis added a comment - re bloom filter rebuilding, if you do it in the index scan loop it will be a lot faster than scanning the data file.
          Stu Hood made changes -
          Assignee Stu Hood [ stuhood ]
          Hide
          Sylvain Lebresne added a comment -

          > In version 0.7, all row keys (which are currently strings encoded as UTF-8, will be returned as raw
          > UTF-8 bytes: Cassandra does not have any idea what you might have encoded in the string.

          Yep, I think I was hoping for some upgrade path that you could customize to repack the keys in
          bytes correctly (by means of a custom java class for instance). But I realized that there is no way
          that could be done without converting all the data of the cluster at once, which is unrealistic. I was
          just stupid. Sorry.

          Show
          Sylvain Lebresne added a comment - > In version 0.7, all row keys (which are currently strings encoded as UTF-8, will be returned as raw > UTF-8 bytes: Cassandra does not have any idea what you might have encoded in the string. Yep, I think I was hoping for some upgrade path that you could customize to repack the keys in bytes correctly (by means of a custom java class for instance). But I realized that there is no way that could be done without converting all the data of the cluster at once, which is unrealistic. I was just stupid. Sorry.
          Hide
          Stu Hood added a comment - - edited

          > Typically, I have to store UUID as row key. Right now I have to encode that in
          > a string somehow.
          In version 0.7, all row keys (which are currently strings encoded as UTF-8), will be returned as raw UTF-8 bytes: Cassandra does not have any idea what you might have encoded in the string.

          Show
          Stu Hood added a comment - - edited > Typically, I have to store UUID as row key. Right now I have to encode that in > a string somehow. In version 0.7, all row keys (which are currently strings encoded as UTF-8), will be returned as raw UTF-8 bytes: Cassandra does not have any idea what you might have encoded in the string.
          Hide
          Sylvain Lebresne added a comment -

          That may well be a question a bit ahead of time, and that may not be the right
          place to ask that, so sorry in advance.
          But do you have any idea of how the upgrade path will work when this come out.
          Do you believe such upgrade will be doable on a live cluster ? Cause I'm not sure
          I see how that can pulled off.

          Typically, I have to store UUID as row key. Right now I have to encode that in
          a string somehow. Ideally, I would like for them to be stored as 16 bytes when
          this patch come out. Not sure how that can be done without a full cluster
          restart tough (which may not be possible at the time).

          Any idea if I can plan something right now (while I'm still in development)
          to make it easier then ?

          Show
          Sylvain Lebresne added a comment - That may well be a question a bit ahead of time, and that may not be the right place to ask that, so sorry in advance. But do you have any idea of how the upgrade path will work when this come out. Do you believe such upgrade will be doable on a live cluster ? Cause I'm not sure I see how that can pulled off. Typically, I have to store UUID as row key. Right now I have to encode that in a string somehow. Ideally, I would like for them to be stored as 16 bytes when this patch come out. Not sure how that can be done without a full cluster restart tough (which may not be possible at the time). Any idea if I can plan something right now (while I'm still in development) to make it easier then ?
          Hide
          Jonathan Ellis added a comment -

          right, it's basically the decorate-sort-undecorate / schwartzian transform pattern.

          Show
          Jonathan Ellis added a comment - right, it's basically the decorate-sort-undecorate / schwartzian transform pattern.
          Hide
          Stu Hood added a comment - - edited

          > An alternative? Instead of AT defining a comparator, have it define a collation id generator
          Works for me... it's similar to what we already do with BytesToken in COPP.

          EDIT: Hmm, except we would still need to solve the padding problems within the collation id.
          EDIT2: Unless the collation id supports the compound key concept somehow by having sections.

          Show
          Stu Hood added a comment - - edited > An alternative? Instead of AT defining a comparator, have it define a collation id generator Works for me... it's similar to what we already do with BytesToken in COPP. EDIT: Hmm, except we would still need to solve the padding problems within the collation id. EDIT2: Unless the collation id supports the compound key concept somehow by having sections.
          Hide
          Jonathan Ellis added a comment -

          that is still outside the scope of 767/16, btw, but i think it's more doable than a comparator-based approach.

          Show
          Jonathan Ellis added a comment - that is still outside the scope of 767/16, btw, but i think it's more doable than a comparator-based approach.
          Hide
          Jonathan Ellis added a comment -

          then you get back to needing partitioner+token per CF. that's totally outside the scope for 0.7 and probably 0.8.

          An alternative? Instead of AT defining a comparator, have it define a collation id generator, where it generates a byte[] that gives it "the right sort" when done lexicographically. then you could make that part of key decoration and it Just Works.

          Show
          Jonathan Ellis added a comment - then you get back to needing partitioner+token per CF. that's totally outside the scope for 0.7 and probably 0.8. An alternative? Instead of AT defining a comparator, have it define a collation id generator, where it generates a byte[] that gives it "the right sort" when done lexicographically. then you could make that part of key decoration and it Just Works.
          Hide
          Stu Hood added a comment - - edited

          Based on the difficulties encountered here, and never wanting to run into them, I think we should allow AbstractTypes per ColumnFamily. This would allow us to do fun stuff like compound keys for our views without throwing away type information and needing to do nasty padding.

          EDIT: er... here: http://brunodumon.wordpress.com/2010/02/17/building-indexes-using-hbase-mapping-strings-numbers-and-dates-onto-bytes/

          Show
          Stu Hood added a comment - - edited Based on the difficulties encountered here, and never wanting to run into them, I think we should allow AbstractTypes per ColumnFamily. This would allow us to do fun stuff like compound keys for our views without throwing away type information and needing to do nasty padding. EDIT: er... here: http://brunodumon.wordpress.com/2010/02/17/building-indexes-using-hbase-mapping-strings-numbers-and-dates-onto-bytes/
          Hide
          Jonathan Ellis added a comment -

          nothing wrong with making everything the equivalent of BytesType to start with and adding support for others later if it turns out to be useful (imo: it won't)

          Show
          Jonathan Ellis added a comment - nothing wrong with making everything the equivalent of BytesType to start with and adding support for others later if it turns out to be useful (imo: it won't)
          Stu Hood made changes -
          Field Original Value New Value
          Link This issue depends on CASSANDRA-389 [ CASSANDRA-389 ]
          Stu Hood created issue -

            People

            • Assignee:
              Stu Hood
              Reporter:
              Stu Hood
            • Votes:
              1 Vote for this issue
              Watchers:
              8 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved:

                Development