sort.tcc 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. // set_key for each kind of key we sort on
  2. template<>
  3. inline void set_key<UidKey>(UidKey *key, const uint8_t *item, uint32_t index)
  4. {
  5. key->uid_index = (uint64_t(*(const uint32_t *)item) << 32) + index;
  6. }
  7. template<>
  8. inline void set_key<UidPriorityKey>(UidPriorityKey *key, const uint8_t *item, uint32_t index)
  9. {
  10. key->uid_priority = (uint64_t(*(const uint32_t *)item) << 32) +
  11. (*(const uint32_t *)(item+4));
  12. key->idx = index;
  13. }
  14. template<>
  15. inline void set_key<NidPriorityKey>(NidPriorityKey *key, const uint8_t *item, uint32_t index)
  16. {
  17. constexpr uint32_t nid_mask = (~((1<<DEST_UID_BITS)-1));
  18. key->nid_priority = (uint64_t((*(const uint32_t *)item)&nid_mask) << 32) +
  19. (*(const uint32_t *)(item+4));
  20. key->idx = index;
  21. }
  22. // compare_keys for each kind of key we sort on. Note that it must not
  23. // be possible for any of these functions to return 0. These functions
  24. // must also be oblivious. Return a positive (32-bit signed) int if *a
  25. // is larger than *b, or a negative (32-bit signed) int otherwise.
  26. template<>
  27. int compare_keys<UidKey>(const void* a, const void* b)
  28. {
  29. bool alarge = (((const UidKey*)a)->uid_index >
  30. ((const UidKey *)b)->uid_index);
  31. return oselect_uint32_t(-1, 1, alarge);
  32. }
  33. template<>
  34. int compare_keys<UidPriorityKey>(const void* a, const void* b)
  35. {
  36. uint64_t aup = ((const UidPriorityKey*)a)->uid_priority;
  37. uint64_t bup = ((const UidPriorityKey*)b)->uid_priority;
  38. uint32_t aidx = ((const UidPriorityKey*)a)->idx;
  39. uint32_t bidx = ((const UidPriorityKey*)b)->idx;
  40. bool auplarge = (aup > bup);
  41. bool aupeq = (aup == bup);
  42. bool aidxlarge = (aidx > bidx);
  43. bool alarge = auplarge | (aupeq & aidxlarge);
  44. return oselect_uint32_t(-1, 1, alarge);
  45. }
  46. template<>
  47. int compare_keys<NidPriorityKey>(const void* a, const void* b)
  48. {
  49. uint64_t anp = ((const NidPriorityKey*)a)->nid_priority;
  50. uint64_t bnp = ((const NidPriorityKey*)b)->nid_priority;
  51. uint32_t aidx = ((const NidPriorityKey*)a)->idx;
  52. uint32_t bidx = ((const NidPriorityKey*)b)->idx;
  53. bool anplarge = (anp > bnp);
  54. bool anpeq = (anp == bnp);
  55. bool aidxlarge = (aidx > bidx);
  56. bool alarge = anplarge | (anpeq & aidxlarge);
  57. return oselect_uint32_t(-1, 1, alarge);
  58. }
  59. // Perform the sort using up to nthreads threads. The items to sort are
  60. // byte arrays of size msg_size. The key is the 10-bit storage server
  61. // id concatenated with the 22-bit uid at the storage server.
  62. template<typename T>
  63. void sort_mtobliv(threadid_t nthreads, uint8_t* items, uint16_t msg_size,
  64. uint32_t Nr, uint32_t Na,
  65. // the arguments to the callback are items, the sorted indices, and
  66. // the number of non-padding items
  67. std::function<void(const uint8_t*, const T*, uint32_t Nr)> cb)
  68. {
  69. // Shuffle the items
  70. uint32_t Nw = shuffle_mtobliv(nthreads, items, msg_size, Nr, Na);
  71. // Create the indices
  72. T *idx = new T[Nr];
  73. T *nextidx = idx;
  74. for (uint32_t i=0; i<Nw; ++i) {
  75. uint64_t padding = (*(uint32_t*)(items+msg_size*i));
  76. if (padding != uint32_t(-1)) {
  77. set_key<T>(nextidx, items+msg_size*i, i);
  78. ++nextidx;
  79. }
  80. }
  81. if (nextidx != idx + Nr) {
  82. printf("Found %u non-padding items, expected %u\n",
  83. nextidx-idx, Nr);
  84. assert(nextidx == idx + Nr);
  85. }
  86. // Sort the keys and indices
  87. T *backingidx = new T[Nr];
  88. bool whichbuf = mtmergesort<T>(idx, Nr, backingidx, nthreads);
  89. T *sortedidx = whichbuf ? backingidx : idx;
  90. cb(items, sortedidx, Nr);
  91. delete[] idx;
  92. delete[] backingidx;
  93. }