base_node.py 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. from dht_common import between, SIZE_OF_HASH, SIZE_OF_IP_ADDRESS
  2. class Base_Node(object):
  3. def __init__(self, nodeID, documentSize, numItems=0, table=[]):
  4. self.nodeID = nodeID
  5. self.nextNode = None
  6. self.documentSize = documentSize
  7. self.numItems = numItems
  8. self.table = dict(table)
  9. self.numRounds = 0
  10. self.numMessagesSent = 0
  11. self.numMessagesRecv = 0
  12. self.numBytesSent = 0
  13. self.numBytesRecv = 0
  14. self.lastNumRounds = 0
  15. self.lastNumMessagesSent = 0
  16. self.lastNumMessagesRecv = 0
  17. self.lastNumBytesSent = 0
  18. self.lastNumBytesRecv = 0
  19. def insert(self):
  20. self.numItems += 1
  21. self.numRounds += 1
  22. self.numMessagesSent += 1
  23. self.numMessagesRecv += 1
  24. self.numBytesSent += SIZE_OF_HASH
  25. self.numBytesRecv += self.documentSize
  26. # There has to be some way of inserting finger table values,
  27. # so this is it (Normally only the DHT should be interfacing with it)
  28. def insert_relation(self, nodeID, fingerTableValue):
  29. # nextNode is kept up to date so that when doing finger table searches,
  30. # we can know when we own something or it needs to go somewhere else
  31. if not self.nextNode or between(nodeID, self.nodeID, self.nextNode):
  32. self.nextNode = nodeID
  33. self.table[nodeID] = fingerTableValue
  34. def retrieve(self):
  35. self.numRounds += 1
  36. self.numMessagesSent += 1
  37. self.numMessagesRecv += 1
  38. self.numBytesSent += self.documentSize
  39. self.numBytesRecv += SIZE_OF_HASH
  40. def get_finger_table_val(self, searchID):
  41. # if we should own this ID, say so
  42. if between(searchID, self.nodeID, self.nextNode):
  43. retval = (self.nodeID, -1)
  44. else: # otherwise, find the best option in the finger table and give that back
  45. options = [x for (x,y) in self.table.items() if x <= searchID]
  46. closest = max(options) if len(options) > 0 else max([x for (x,y) in self.table.items()])
  47. retval = (closest, self.table[closest])
  48. self.numRounds += 1
  49. self.numMessagesSent += 1
  50. self.numMessagesRecv += 1
  51. self.numBytesSent += SIZE_OF_HASH + SIZE_OF_IP_ADDRESS
  52. self.numBytesRecv += SIZE_OF_HASH
  53. return retval
  54. def get_num_rounds(self):
  55. self.lastNumRounds = self.numRounds
  56. return self.numRounds
  57. def get_recent_num_rounds(self):
  58. retval = self.numRounds - self.lastNumRounds
  59. self.lastNumRounds = self.numRounds
  60. return retval
  61. def get_num_messages_sent(self):
  62. self.lastNumMessagesSent = self.numMessagesSent
  63. return self.numMessagesSent
  64. def get_recent_num_messages_sent(self):
  65. retval = self.numMessagesSent - self.lastNumMessagesSent
  66. self.lastNumMessagesSent = self.numMessagesSent
  67. return retval
  68. def get_num_messages_recv(self):
  69. self.lastNumMessagesRecv = self.numMessagesRecv
  70. return self.numMessagesRecv
  71. def get_recent_num_messages_recv(self):
  72. retval = self.numMessagesRecv - self.lastNumMessagesRecv
  73. self.lastNumMessagesRecv = self.numMessagesRecv
  74. return retval
  75. def get_num_bytes_sent(self):
  76. self.lastNumBytesSent = self.numBytesSent
  77. return self.numBytesSent
  78. def get_recent_num_bytes_sent(self):
  79. retval = self.numBytesSent - self.lastNumBytesSent
  80. self.lastNumBytesSent = self.numBytesSent
  81. return retval
  82. def get_num_bytes_recv(self):
  83. self.lastNumBytesRecv = self.numBytesRecv
  84. return self.numBytesRecv
  85. def get_recent_num_bytes_recv(self):
  86. retval = self.numBytesRecv - self.lastNumBytesRecv
  87. self.lastNumBytesRecv = self.numBytesRecv
  88. return retval
  89. # Normally this file is a class to be used elsewhere,
  90. # but if you run it directly it performs some rudimentary unit tests
  91. # TODO: Add unit tests for size calculations
  92. if __name__ == "__main__":
  93. SIZE_OF_DOCUMENTS_IN_TEST = 1024
  94. test = Base_Node(0, SIZE_OF_DOCUMENTS_IN_TEST)
  95. [test.insert(x, x) for x in range(10)]
  96. retrievals = [test.retrieve(x) for x in range(10)]
  97. print("Insert and retrieval fires correctly.")
  98. test.retrieve("nothere")
  99. print("Nonexistant entries fires correctly.")
  100. test.insert_relation(1, 1)
  101. test.insert_relation(2, 2)
  102. test.insert_relation(4, 4)
  103. test.insert_relation(8, 8)
  104. assert test.get_finger_table_val(1) == (1, 1)
  105. assert test.get_finger_table_val(3) == (2, 2)
  106. assert test.get_finger_table_val(4) == (4, 4)
  107. assert test.get_finger_table_val(7) == (4, 4)
  108. assert test.get_finger_table_val(0) == (0, -1)
  109. print("Finger table stuff working correctly")