fdc7148276add47ba0a8f8b754e7a9dc6369f1e68bf029a698c5690071af299fa84208df449306d4590fb9b59c02e410482b61b5ffd8353294262ff9f87c50 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. #include "DirTree.hh"
  2. #include <inttypes.h>
  3. static std::mutex mDirCacheMutex;
  4. static std::unordered_map<std::string, std::weak_ptr<DirTree>> dirTreeCache;
  5. struct DirTreeDeleter {
  6. void operator()(DirTree *tree) {
  7. std::lock_guard<std::mutex> lock(mDirCacheMutex);
  8. dirTreeCache.erase(tree->root);
  9. delete tree;
  10. // Free up memory.
  11. if (dirTreeCache.size() == 0) {
  12. dirTreeCache.rehash(0);
  13. }
  14. }
  15. };
  16. std::shared_ptr<DirTree> DirTree::getCached(std::string root) {
  17. std::lock_guard<std::mutex> lock(mDirCacheMutex);
  18. auto found = dirTreeCache.find(root);
  19. std::shared_ptr<DirTree> tree;
  20. // Use cached tree, or create an empty one.
  21. if (found != dirTreeCache.end()) {
  22. tree = found->second.lock();
  23. } else {
  24. tree = std::shared_ptr<DirTree>(new DirTree(root), DirTreeDeleter());
  25. dirTreeCache.emplace(root, tree);
  26. }
  27. return tree;
  28. }
  29. DirTree::DirTree(std::string root, FILE *f) : root(root), isComplete(true) {
  30. size_t size;
  31. if (fscanf(f, "%zu", &size)) {
  32. for (size_t i = 0; i < size; i++) {
  33. DirEntry entry(f);
  34. entries.emplace(entry.path, entry);
  35. }
  36. }
  37. }
  38. // Internal find method that has no lock
  39. DirEntry *DirTree::_find(std::string path) {
  40. auto found = entries.find(path);
  41. if (found == entries.end()) {
  42. return NULL;
  43. }
  44. return &found->second;
  45. }
  46. DirEntry *DirTree::add(std::string path, uint64_t mtime, bool isDir) {
  47. std::lock_guard<std::mutex> lock(mMutex);
  48. DirEntry entry(path, mtime, isDir);
  49. auto it = entries.emplace(entry.path, entry);
  50. return &it.first->second;
  51. }
  52. DirEntry *DirTree::find(std::string path) {
  53. std::lock_guard<std::mutex> lock(mMutex);
  54. return _find(path);
  55. }
  56. DirEntry *DirTree::update(std::string path, uint64_t mtime) {
  57. std::lock_guard<std::mutex> lock(mMutex);
  58. DirEntry *found = _find(path);
  59. if (found) {
  60. found->mtime = mtime;
  61. }
  62. return found;
  63. }
  64. void DirTree::remove(std::string path) {
  65. std::lock_guard<std::mutex> lock(mMutex);
  66. DirEntry *found = _find(path);
  67. // Remove all sub-entries if this is a directory
  68. if (found && found->isDir) {
  69. std::string pathStart = path + DIR_SEP;
  70. for (auto it = entries.begin(); it != entries.end();) {
  71. if (it->first.rfind(pathStart, 0) == 0) {
  72. it = entries.erase(it);
  73. } else {
  74. it++;
  75. }
  76. }
  77. }
  78. entries.erase(path);
  79. }
  80. void DirTree::write(FILE *f) {
  81. std::lock_guard<std::mutex> lock(mMutex);
  82. fprintf(f, "%zu\n", entries.size());
  83. for (auto it = entries.begin(); it != entries.end(); it++) {
  84. it->second.write(f);
  85. }
  86. }
  87. void DirTree::getChanges(DirTree *snapshot, EventList &events) {
  88. std::lock_guard<std::mutex> lock(mMutex);
  89. std::lock_guard<std::mutex> snapshotLock(snapshot->mMutex);
  90. for (auto it = entries.begin(); it != entries.end(); it++) {
  91. auto found = snapshot->entries.find(it->first);
  92. if (found == snapshot->entries.end()) {
  93. events.create(it->second.path);
  94. } else if (found->second.mtime != it->second.mtime && !found->second.isDir && !it->second.isDir) {
  95. events.update(it->second.path);
  96. }
  97. }
  98. for (auto it = snapshot->entries.begin(); it != snapshot->entries.end(); it++) {
  99. size_t count = entries.count(it->first);
  100. if (count == 0) {
  101. events.remove(it->second.path);
  102. }
  103. }
  104. }
  105. DirEntry::DirEntry(std::string p, uint64_t t, bool d) {
  106. path = p;
  107. mtime = t;
  108. isDir = d;
  109. state = NULL;
  110. }
  111. DirEntry::DirEntry(FILE *f) {
  112. size_t size;
  113. if (fscanf(f, "%zu", &size)) {
  114. path.resize(size);
  115. if (fread(&path[0], sizeof(char), size, f)) {
  116. int d = 0;
  117. fscanf(f, "%" PRIu64 " %d\n", &mtime, &d);
  118. isDir = d == 1;
  119. }
  120. }
  121. }
  122. void DirEntry::write(FILE *f) const {
  123. fprintf(f, "%zu%s%" PRIu64 " %d\n", path.size(), path.c_str(), mtime, isDir);
  124. }