]> git.apps.os.sepia.ceph.com Git - ceph-ci.git/commitdiff
rbd-mirror: introduce generalized mirror entity (type, global_id, size)
authorMykola Golub <mgolub@suse.com>
Wed, 30 Dec 2020 16:37:31 +0000 (16:37 +0000)
committerIlya Dryomov <idryomov@gmail.com>
Sun, 28 Sep 2025 18:24:59 +0000 (20:24 +0200)
where type may be image or group. Make pool watcher and image
mapper use it currently for images. The group support is coming.

Signed-off-by: Mykola Golub <mgolub@suse.com>
Signed-off-by: Prasanna Kumar Kalever <prasanna.kalever@redhat.com>
32 files changed:
src/test/rbd_mirror/CMakeLists.txt
src/test/rbd_mirror/image_map/test_Policy.cc
src/test/rbd_mirror/pool_watcher/test_mock_RefreshEntitiesRequest.cc [new file with mode: 0644]
src/test/rbd_mirror/pool_watcher/test_mock_RefreshImagesRequest.cc [deleted file]
src/test/rbd_mirror/test_PoolWatcher.cc
src/test/rbd_mirror/test_mock_ImageMap.cc
src/test/rbd_mirror/test_mock_NamespaceReplayer.cc
src/test/rbd_mirror/test_mock_PoolWatcher.cc
src/tools/rbd_mirror/CMakeLists.txt
src/tools/rbd_mirror/ImageMap.cc
src/tools/rbd_mirror/ImageMap.h
src/tools/rbd_mirror/NamespaceReplayer.cc
src/tools/rbd_mirror/NamespaceReplayer.h
src/tools/rbd_mirror/PoolWatcher.cc
src/tools/rbd_mirror/PoolWatcher.h
src/tools/rbd_mirror/Types.cc
src/tools/rbd_mirror/Types.h
src/tools/rbd_mirror/image_map/LoadRequest.cc
src/tools/rbd_mirror/image_map/LoadRequest.h
src/tools/rbd_mirror/image_map/Policy.cc
src/tools/rbd_mirror/image_map/Policy.h
src/tools/rbd_mirror/image_map/SimplePolicy.cc
src/tools/rbd_mirror/image_map/SimplePolicy.h
src/tools/rbd_mirror/image_map/Types.cc
src/tools/rbd_mirror/image_map/Types.h
src/tools/rbd_mirror/image_map/UpdateRequest.cc
src/tools/rbd_mirror/image_map/UpdateRequest.h
src/tools/rbd_mirror/pool_watcher/RefreshEntitiesRequest.cc [new file with mode: 0644]
src/tools/rbd_mirror/pool_watcher/RefreshEntitiesRequest.h [new file with mode: 0644]
src/tools/rbd_mirror/pool_watcher/RefreshImagesRequest.cc [deleted file]
src/tools/rbd_mirror/pool_watcher/RefreshImagesRequest.h [deleted file]
src/tools/rbd_mirror/pool_watcher/Types.h

index 1226735d546594d026b8f5484de2309ec6536e0f..821f1051af2a600762add41eee413fc0f762f73e 100644 (file)
@@ -47,7 +47,7 @@ add_executable(unittest_rbd_mirror
   image_replayer/snapshot/test_mock_Replayer.cc
   image_sync/test_mock_SyncPointCreateRequest.cc
   image_sync/test_mock_SyncPointPruneRequest.cc
-  pool_watcher/test_mock_RefreshImagesRequest.cc
+  pool_watcher/test_mock_RefreshEntitiesRequest.cc
   )
 add_ceph_unittest(unittest_rbd_mirror)
 
index e60ffbfd53cf986dd89c83d40cac3b5f12dd12a3..bc4e0bcfa648e33eecc95550e18556b426ea6ab9 100644 (file)
@@ -41,34 +41,43 @@ public:
   }
 
   void map_image(const std::string &global_image_id) {
-    ASSERT_TRUE(m_policy->add_image(global_image_id));
+    auto global_id = image_map::GlobalId(MIRROR_ENTITY_TYPE_IMAGE,
+                                         global_image_id);
 
-    ASSERT_EQ(ACTION_TYPE_MAP_UPDATE, m_policy->start_action(global_image_id));
-    ASSERT_TRUE(m_policy->finish_action(global_image_id, 0));
+    ASSERT_TRUE(m_policy->add_entity(global_id, 1));
 
-    ASSERT_EQ(ACTION_TYPE_ACQUIRE, m_policy->start_action(global_image_id));
-    ASSERT_FALSE(m_policy->finish_action(global_image_id, 0));
+    ASSERT_EQ(ACTION_TYPE_MAP_UPDATE, m_policy->start_action(global_id));
+    ASSERT_TRUE(m_policy->finish_action(global_id, 0));
+
+    ASSERT_EQ(ACTION_TYPE_ACQUIRE, m_policy->start_action(global_id));
+    ASSERT_FALSE(m_policy->finish_action(global_id, 0));
   }
 
   void unmap_image(const std::string &global_image_id) {
-    ASSERT_TRUE(m_policy->remove_image(global_image_id));
+    auto global_id = image_map::GlobalId(MIRROR_ENTITY_TYPE_IMAGE,
+                                         global_image_id);
+
+    ASSERT_TRUE(m_policy->remove_entity(global_id));
 
-    ASSERT_EQ(ACTION_TYPE_RELEASE, m_policy->start_action(global_image_id));
-    ASSERT_TRUE(m_policy->finish_action(global_image_id, 0));
+    ASSERT_EQ(ACTION_TYPE_RELEASE, m_policy->start_action(global_id));
+    ASSERT_TRUE(m_policy->finish_action(global_id, 0));
 
-    ASSERT_EQ(ACTION_TYPE_MAP_REMOVE, m_policy->start_action(global_image_id));
-    ASSERT_FALSE(m_policy->finish_action(global_image_id, 0));
+    ASSERT_EQ(ACTION_TYPE_MAP_REMOVE, m_policy->start_action(global_id));
+    ASSERT_FALSE(m_policy->finish_action(global_id, 0));
   }
 
   void shuffle_image(const std::string &global_image_id) {
-    ASSERT_EQ(ACTION_TYPE_RELEASE, m_policy->start_action(global_image_id));
-    ASSERT_TRUE(m_policy->finish_action(global_image_id, 0));
+    auto global_id = image_map::GlobalId(MIRROR_ENTITY_TYPE_IMAGE,
+                                         global_image_id);
+
+    ASSERT_EQ(ACTION_TYPE_RELEASE, m_policy->start_action(global_id));
+    ASSERT_TRUE(m_policy->finish_action(global_id, 0));
 
-    ASSERT_EQ(ACTION_TYPE_MAP_UPDATE, m_policy->start_action(global_image_id));
-    ASSERT_TRUE(m_policy->finish_action(global_image_id, 0));
+    ASSERT_EQ(ACTION_TYPE_MAP_UPDATE, m_policy->start_action(global_id));
+    ASSERT_TRUE(m_policy->finish_action(global_id, 0));
 
-    ASSERT_EQ(ACTION_TYPE_ACQUIRE, m_policy->start_action(global_image_id));
-    ASSERT_FALSE(m_policy->finish_action(global_image_id, 0));
+    ASSERT_EQ(ACTION_TYPE_ACQUIRE, m_policy->start_action(global_id));
+    ASSERT_FALSE(m_policy->finish_action(global_id, 0));
   }
 
   Policy *m_policy;
@@ -77,14 +86,16 @@ public:
 TEST_F(TestImageMapPolicy, NegativeLookup) {
   const std::string global_image_id = "global id 1";
 
-  LookupInfo info = m_policy->lookup(global_image_id);
+  LookupInfo info = m_policy->lookup({MIRROR_ENTITY_TYPE_IMAGE,
+                                      global_image_id});
   ASSERT_TRUE(info.instance_id == UNMAPPED_INSTANCE_ID);
 }
 
 TEST_F(TestImageMapPolicy, Init) {
   const std::string global_image_id = "global id 1";
 
-  m_policy->init({{global_image_id, {"9876", {}, {}}}});
+  m_policy->init({{{MIRROR_ENTITY_TYPE_IMAGE, global_image_id},
+                   {"9876", {}, {}}}});
 
   ASSERT_EQ(ACTION_TYPE_ACQUIRE, m_policy->start_action(global_image_id));
   ASSERT_FALSE(m_policy->finish_action(global_image_id, 0));
@@ -95,7 +106,8 @@ TEST_F(TestImageMapPolicy, MapImage) {
 
   map_image(global_image_id);
 
-  LookupInfo info = m_policy->lookup(global_image_id);
+  LookupInfo info = m_policy->lookup({MIRROR_ENTITY_TYPE_IMAGE,
+                                      global_image_id});
   ASSERT_TRUE(info.instance_id != UNMAPPED_INSTANCE_ID);
 }
 
@@ -105,13 +117,14 @@ TEST_F(TestImageMapPolicy, UnmapImage) {
   // map image
   map_image(global_image_id);
 
-  LookupInfo info = m_policy->lookup(global_image_id);
+  LookupInfo info = m_policy->lookup({MIRROR_ENTITY_TYPE_IMAGE,
+                                      global_image_id});
   ASSERT_TRUE(info.instance_id != UNMAPPED_INSTANCE_ID);
 
   // unmap image
   unmap_image(global_image_id);
 
-  info = m_policy->lookup(global_image_id);
+  info = m_policy->lookup({MIRROR_ENTITY_TYPE_IMAGE, global_image_id});
   ASSERT_TRUE(info.instance_id == UNMAPPED_INSTANCE_ID);
 }
 
@@ -124,17 +137,19 @@ TEST_F(TestImageMapPolicy, ShuffleImageAddInstance) {
     // map image
     map_image(global_image_id);
 
-    LookupInfo info = m_policy->lookup(global_image_id);
+    LookupInfo info = m_policy->lookup({MIRROR_ENTITY_TYPE_IMAGE,
+                                        global_image_id});
     ASSERT_TRUE(info.instance_id != UNMAPPED_INSTANCE_ID);
   }
 
-  std::set<std::string> shuffle_global_image_ids;
-  m_policy->add_instances({"9876"}, &shuffle_global_image_ids);
+  image_map::GlobalIds shuffle_global_ids;
+  m_policy->add_instances({"9876"}, &shuffle_global_ids);
 
-  for (auto const &global_image_id : shuffle_global_image_ids) {
-    shuffle_image(global_image_id);
+  for (auto const &global_id : shuffle_global_ids) {
+    ASSERT_EQ(global_id.type, MIRROR_ENTITY_TYPE_IMAGE);
+    shuffle_image(global_id.id);
 
-    LookupInfo info = m_policy->lookup(global_image_id);
+    LookupInfo info = m_policy->lookup(global_id);
     ASSERT_TRUE(info.instance_id != UNMAPPED_INSTANCE_ID);
   }
 }
@@ -144,103 +159,107 @@ TEST_F(TestImageMapPolicy, ShuffleImageRemoveInstance) {
     "global id 1", "global id 2", "global id 3", "global id 4", "global id 5"
   };
 
-  std::set<std::string> shuffle_global_image_ids;
+  image_map::GlobalIds shuffle_global_ids;
   m_policy->add_instances({stringify(m_local_io_ctx.get_instance_id())},
-                          &shuffle_global_image_ids);
+                          &shuffle_global_ids);
   for (auto const &global_image_id : global_image_ids) {
     // map image
     map_image(global_image_id);
 
-    LookupInfo info = m_policy->lookup(global_image_id);
+    LookupInfo info = m_policy->lookup({MIRROR_ENTITY_TYPE_IMAGE,
+                                        global_image_id});
     ASSERT_TRUE(info.instance_id != UNMAPPED_INSTANCE_ID);
   }
 
-  m_policy->add_instances({"9876"}, &shuffle_global_image_ids);
+  m_policy->add_instances({"9876"}, &shuffle_global_ids);
 
-  for (auto const &global_image_id : shuffle_global_image_ids) {
-    shuffle_image(global_image_id);
+  for (auto const &global_id : shuffle_global_ids) {
+    ASSERT_EQ(global_id.type, MIRROR_ENTITY_TYPE_IMAGE);
+    shuffle_image(global_id.id);
 
-    LookupInfo info = m_policy->lookup(global_image_id);
+    LookupInfo info = m_policy->lookup(global_id);
     ASSERT_TRUE(info.instance_id != UNMAPPED_INSTANCE_ID);
   }
 
   // record which of the images got migrated to the new instance
-  std::set<std::string> remapped_global_image_ids;
-  for (auto const &global_image_id: shuffle_global_image_ids) {
-    LookupInfo info = m_policy->lookup(global_image_id);
+  image_map::GlobalIds remapped_global_ids;
+  for (auto const &global_id: shuffle_global_ids) {
+    LookupInfo info = m_policy->lookup(global_id);
     if (info.instance_id == "9876") {
-      remapped_global_image_ids.emplace(global_image_id);
+      remapped_global_ids.emplace(global_id);
     }
   }
 
-  shuffle_global_image_ids.clear();
-  m_policy->remove_instances({"9876"}, &shuffle_global_image_ids);
+  shuffle_global_ids.clear();
+  m_policy->remove_instances({"9876"}, &shuffle_global_ids);
 
-  ASSERT_TRUE(shuffle_global_image_ids == remapped_global_image_ids);
+  ASSERT_TRUE(shuffle_global_ids == remapped_global_ids);
 
-  for (auto const &global_image_id : shuffle_global_image_ids) {
-    shuffle_image(global_image_id);
+  for (auto const &global_id : shuffle_global_ids) {
+    shuffle_image(global_id.id);
 
-    LookupInfo info = m_policy->lookup(global_image_id);
+    LookupInfo info = m_policy->lookup(global_id);
     ASSERT_TRUE(info.instance_id != UNMAPPED_INSTANCE_ID);
   }
 }
 
 TEST_F(TestImageMapPolicy, RetryMapUpdate) {
-  const std::string global_image_id = "global id 1";
+  auto global_id = image_map::GlobalId(MIRROR_ENTITY_TYPE_IMAGE,
+                                       "global id 1");
 
-  ASSERT_TRUE(m_policy->add_image(global_image_id));
+  ASSERT_TRUE(m_policy->add_entity(global_id, 1));
 
-  ASSERT_EQ(ACTION_TYPE_MAP_UPDATE, m_policy->start_action(global_image_id));
+  ASSERT_EQ(ACTION_TYPE_MAP_UPDATE, m_policy->start_action(global_id));
   // on-disk map update failed
-  ASSERT_TRUE(m_policy->finish_action(global_image_id, -EIO));
+  ASSERT_TRUE(m_policy->finish_action(global_id, -EIO));
 
-  ASSERT_EQ(ACTION_TYPE_MAP_UPDATE, m_policy->start_action(global_image_id));
-  ASSERT_TRUE(m_policy->finish_action(global_image_id, 0));
+  ASSERT_EQ(ACTION_TYPE_MAP_UPDATE, m_policy->start_action(global_id));
+  ASSERT_TRUE(m_policy->finish_action(global_id, 0));
 
-  ASSERT_EQ(ACTION_TYPE_ACQUIRE, m_policy->start_action(global_image_id));
-  ASSERT_FALSE(m_policy->finish_action(global_image_id, 0));
+  ASSERT_EQ(ACTION_TYPE_ACQUIRE, m_policy->start_action(global_id));
+  ASSERT_FALSE(m_policy->finish_action(global_id, 0));
 
-  LookupInfo info = m_policy->lookup(global_image_id);
+  LookupInfo info = m_policy->lookup(global_id);
   ASSERT_TRUE(info.instance_id != UNMAPPED_INSTANCE_ID);
 }
 
 TEST_F(TestImageMapPolicy, MapFailureAndUnmap) {
-  const std::string global_image_id = "global id 1";
+  auto global_id = image_map::GlobalId(MIRROR_ENTITY_TYPE_IMAGE,
+                                       "global id 1");
 
-  ASSERT_TRUE(m_policy->add_image(global_image_id));
+  ASSERT_TRUE(m_policy->add_entity(global_id, 1));
 
-  ASSERT_EQ(ACTION_TYPE_MAP_UPDATE, m_policy->start_action(global_image_id));
-  ASSERT_TRUE(m_policy->finish_action(global_image_id, 0));
+  ASSERT_EQ(ACTION_TYPE_MAP_UPDATE, m_policy->start_action(global_id));
+  ASSERT_TRUE(m_policy->finish_action(global_id, 0));
 
-  ASSERT_EQ(ACTION_TYPE_ACQUIRE, m_policy->start_action(global_image_id));
+  ASSERT_EQ(ACTION_TYPE_ACQUIRE, m_policy->start_action(global_id));
 
-  std::set<std::string> shuffle_global_image_ids;
-  m_policy->add_instances({"9876"}, &shuffle_global_image_ids);
-  ASSERT_TRUE(shuffle_global_image_ids.empty());
+  image_map::GlobalIds shuffle_global_ids;
+  m_policy->add_instances({"9876"}, &shuffle_global_ids);
+  ASSERT_TRUE(shuffle_global_ids.empty());
 
   m_policy->remove_instances({stringify(m_local_io_ctx.get_instance_id())},
-                             &shuffle_global_image_ids);
-  ASSERT_TRUE(shuffle_global_image_ids.empty());
+                             &shuffle_global_ids);
+  ASSERT_TRUE(shuffle_global_ids.empty());
 
-  ASSERT_TRUE(m_policy->finish_action(global_image_id, -EBLOCKLISTED));
+  ASSERT_TRUE(m_policy->finish_action(global_id, -EBLOCKLISTED));
 
-  ASSERT_EQ(ACTION_TYPE_RELEASE, m_policy->start_action(global_image_id));
-  ASSERT_TRUE(m_policy->finish_action(global_image_id, -ENOENT));
+  ASSERT_EQ(ACTION_TYPE_RELEASE, m_policy->start_action(global_id));
+  ASSERT_TRUE(m_policy->finish_action(global_id, -ENOENT));
 
-  ASSERT_EQ(ACTION_TYPE_MAP_UPDATE, m_policy->start_action(global_image_id));
-  ASSERT_TRUE(m_policy->finish_action(global_image_id, 0));
+  ASSERT_EQ(ACTION_TYPE_MAP_UPDATE, m_policy->start_action(global_id));
+  ASSERT_TRUE(m_policy->finish_action(global_id, 0));
 
-  ASSERT_EQ(ACTION_TYPE_ACQUIRE, m_policy->start_action(global_image_id));
-  ASSERT_FALSE(m_policy->finish_action(global_image_id, 0));
+  ASSERT_EQ(ACTION_TYPE_ACQUIRE, m_policy->start_action(global_id));
+  ASSERT_FALSE(m_policy->finish_action(global_id, 0));
 
-  ASSERT_TRUE(m_policy->remove_image(global_image_id));
+  ASSERT_TRUE(m_policy->remove_entity(global_id));
 
-  ASSERT_EQ(ACTION_TYPE_RELEASE, m_policy->start_action(global_image_id));
-  ASSERT_TRUE(m_policy->finish_action(global_image_id, 0));
+  ASSERT_EQ(ACTION_TYPE_RELEASE, m_policy->start_action(global_id));
+  ASSERT_TRUE(m_policy->finish_action(global_id, 0));
 
-  ASSERT_EQ(ACTION_TYPE_MAP_REMOVE, m_policy->start_action(global_image_id));
-  ASSERT_FALSE(m_policy->finish_action(global_image_id, 0));
+  ASSERT_EQ(ACTION_TYPE_MAP_REMOVE, m_policy->start_action(global_id));
+  ASSERT_FALSE(m_policy->finish_action(global_id, 0));
 }
 
 TEST_F(TestImageMapPolicy, ReshuffleWithMapFailure) {
@@ -249,45 +268,46 @@ TEST_F(TestImageMapPolicy, ReshuffleWithMapFailure) {
     "global id 6"
   };
 
-  std::set<std::string> shuffle_global_image_ids;
+  image_map::GlobalIds shuffle_global_ids;
   m_policy->add_instances({stringify(m_local_io_ctx.get_instance_id())},
-                          &shuffle_global_image_ids);
+                          &shuffle_global_ids);
   for (auto const &global_image_id : global_image_ids) {
     // map image
     map_image(global_image_id);
 
-    LookupInfo info = m_policy->lookup(global_image_id);
+    LookupInfo info = m_policy->lookup({MIRROR_ENTITY_TYPE_IMAGE,
+                                        global_image_id});
     ASSERT_TRUE(info.instance_id != UNMAPPED_INSTANCE_ID);
   }
 
-  m_policy->add_instances({"9876"}, &shuffle_global_image_ids);
-  ASSERT_FALSE(shuffle_global_image_ids.empty());
+  m_policy->add_instances({"9876"}, &shuffle_global_ids);
+  ASSERT_FALSE(shuffle_global_ids.empty());
 
-  const std::string global_image_id = *(shuffle_global_image_ids.begin());
-  shuffle_global_image_ids.clear();
+  auto global_id = *(shuffle_global_ids.begin());
+  shuffle_global_ids.clear();
 
-  ASSERT_EQ(ACTION_TYPE_RELEASE, m_policy->start_action(global_image_id));
-  ASSERT_TRUE(m_policy->finish_action(global_image_id, 0));
+  ASSERT_EQ(ACTION_TYPE_RELEASE, m_policy->start_action(global_id));
+  ASSERT_TRUE(m_policy->finish_action(global_id, 0));
 
-  ASSERT_EQ(ACTION_TYPE_MAP_UPDATE, m_policy->start_action(global_image_id));
-  ASSERT_TRUE(m_policy->finish_action(global_image_id, 0));
+  ASSERT_EQ(ACTION_TYPE_MAP_UPDATE, m_policy->start_action(global_id));
+  ASSERT_TRUE(m_policy->finish_action(global_id, 0));
 
-  ASSERT_EQ(ACTION_TYPE_ACQUIRE, m_policy->start_action(global_image_id));
+  ASSERT_EQ(ACTION_TYPE_ACQUIRE, m_policy->start_action(global_id));
 
   // peer unavailable
-  m_policy->remove_instances({"9876"}, &shuffle_global_image_ids);
-  ASSERT_TRUE(shuffle_global_image_ids.empty());
+  m_policy->remove_instances({"9876"}, &shuffle_global_ids);
+  ASSERT_TRUE(shuffle_global_ids.empty());
 
-  ASSERT_TRUE(m_policy->finish_action(global_image_id, -EBLOCKLISTED));
+  ASSERT_TRUE(m_policy->finish_action(global_id, -EBLOCKLISTED));
 
-  ASSERT_EQ(ACTION_TYPE_RELEASE, m_policy->start_action(global_image_id));
-  ASSERT_TRUE(m_policy->finish_action(global_image_id, 0));
+  ASSERT_EQ(ACTION_TYPE_RELEASE, m_policy->start_action(global_id));
+  ASSERT_TRUE(m_policy->finish_action(global_id, 0));
 
-  ASSERT_EQ(ACTION_TYPE_MAP_UPDATE, m_policy->start_action(global_image_id));
-  ASSERT_TRUE(m_policy->finish_action(global_image_id, 0));
+  ASSERT_EQ(ACTION_TYPE_MAP_UPDATE, m_policy->start_action(global_id));
+  ASSERT_TRUE(m_policy->finish_action(global_id, 0));
 
-  ASSERT_EQ(ACTION_TYPE_ACQUIRE, m_policy->start_action(global_image_id));
-  ASSERT_FALSE(m_policy->finish_action(global_image_id, 0));
+  ASSERT_EQ(ACTION_TYPE_ACQUIRE, m_policy->start_action(global_id));
+  ASSERT_FALSE(m_policy->finish_action(global_id, 0));
 }
 
 TEST_F(TestImageMapPolicy, ShuffleFailureAndRemove) {
@@ -296,80 +316,82 @@ TEST_F(TestImageMapPolicy, ShuffleFailureAndRemove) {
     "global id 6"
   };
 
-  std::set<std::string> shuffle_global_image_ids;
+  image_map::GlobalIds shuffle_global_ids;
   m_policy->add_instances({stringify(m_local_io_ctx.get_instance_id())},
-                          &shuffle_global_image_ids);
+                          &shuffle_global_ids);
   for (auto const &global_image_id : global_image_ids) {
     // map image
     map_image(global_image_id);
 
-    LookupInfo info = m_policy->lookup(global_image_id);
+    LookupInfo info = m_policy->lookup({MIRROR_ENTITY_TYPE_IMAGE,
+                                        global_image_id});
     ASSERT_TRUE(info.instance_id != UNMAPPED_INSTANCE_ID);
   }
 
-  m_policy->add_instances({"9876"}, &shuffle_global_image_ids);
-  ASSERT_FALSE(shuffle_global_image_ids.empty());
+  m_policy->add_instances({"9876"}, &shuffle_global_ids);
+  ASSERT_FALSE(shuffle_global_ids.empty());
 
-  std::string global_image_id = *(shuffle_global_image_ids.begin());
-  shuffle_global_image_ids.clear();
+  auto global_id = *(shuffle_global_ids.begin());
+  shuffle_global_ids.clear();
 
-  ASSERT_EQ(ACTION_TYPE_RELEASE, m_policy->start_action(global_image_id));
-  ASSERT_TRUE(m_policy->finish_action(global_image_id, 0));
+  ASSERT_EQ(ACTION_TYPE_RELEASE, m_policy->start_action(global_id));
+  ASSERT_TRUE(m_policy->finish_action(global_id, 0));
 
-  ASSERT_EQ(ACTION_TYPE_MAP_UPDATE, m_policy->start_action(global_image_id));
-  ASSERT_TRUE(m_policy->finish_action(global_image_id, 0));
+  ASSERT_EQ(ACTION_TYPE_MAP_UPDATE, m_policy->start_action(global_id));
+  ASSERT_TRUE(m_policy->finish_action(global_id, 0));
 
-  ASSERT_EQ(ACTION_TYPE_ACQUIRE, m_policy->start_action(global_image_id));
+  ASSERT_EQ(ACTION_TYPE_ACQUIRE, m_policy->start_action(global_id));
 
   // peer unavailable
-  m_policy->remove_instances({"9876"}, &shuffle_global_image_ids);
-  ASSERT_TRUE(shuffle_global_image_ids.empty());
+  m_policy->remove_instances({"9876"}, &shuffle_global_ids);
+  ASSERT_TRUE(shuffle_global_ids.empty());
 
-  ASSERT_TRUE(m_policy->finish_action(global_image_id, -EBLOCKLISTED));
+  ASSERT_TRUE(m_policy->finish_action(global_id, -EBLOCKLISTED));
 
-  ASSERT_EQ(ACTION_TYPE_RELEASE, m_policy->start_action(global_image_id));
-  ASSERT_TRUE(m_policy->finish_action(global_image_id, 0));
+  ASSERT_EQ(ACTION_TYPE_RELEASE, m_policy->start_action(global_id));
+  ASSERT_TRUE(m_policy->finish_action(global_id, 0));
 
-  ASSERT_EQ(ACTION_TYPE_MAP_UPDATE, m_policy->start_action(global_image_id));
-  ASSERT_TRUE(m_policy->finish_action(global_image_id, 0));
+  ASSERT_EQ(ACTION_TYPE_MAP_UPDATE, m_policy->start_action(global_id));
+  ASSERT_TRUE(m_policy->finish_action(global_id, 0));
 
-  ASSERT_EQ(ACTION_TYPE_ACQUIRE, m_policy->start_action(global_image_id));
-  ASSERT_FALSE(m_policy->finish_action(global_image_id, 0));
+  ASSERT_EQ(ACTION_TYPE_ACQUIRE, m_policy->start_action(global_id));
+  ASSERT_FALSE(m_policy->finish_action(global_id, 0));
 
-  ASSERT_TRUE(m_policy->remove_image(global_image_id));
+  ASSERT_TRUE(m_policy->remove_entity(global_id));
 
-  ASSERT_EQ(ACTION_TYPE_RELEASE, m_policy->start_action(global_image_id));
-  ASSERT_TRUE(m_policy->finish_action(global_image_id, 0));
+  ASSERT_EQ(ACTION_TYPE_RELEASE, m_policy->start_action(global_id));
+  ASSERT_TRUE(m_policy->finish_action(global_id, 0));
 
-  ASSERT_EQ(ACTION_TYPE_MAP_REMOVE, m_policy->start_action(global_image_id));
-  ASSERT_FALSE(m_policy->finish_action(global_image_id, 0));
+  ASSERT_EQ(ACTION_TYPE_MAP_REMOVE, m_policy->start_action(global_id));
+  ASSERT_FALSE(m_policy->finish_action(global_id, 0));
 
-  LookupInfo info = m_policy->lookup(global_image_id);
+  LookupInfo info = m_policy->lookup(global_id);
   ASSERT_TRUE(info.instance_id == UNMAPPED_INSTANCE_ID);
 }
 
 TEST_F(TestImageMapPolicy, InitialInstanceUpdate) {
-  const std::string global_image_id = "global id 1";
+  auto global_id = image_map::GlobalId(MIRROR_ENTITY_TYPE_IMAGE,
+                                       "global id 1");
 
-  m_policy->init({{global_image_id, {"9876", {}, {}}}});
+  m_policy->init({{global_id, {"9876", {}, {}}}});
 
-  ASSERT_EQ(ACTION_TYPE_ACQUIRE, m_policy->start_action(global_image_id));
+  ASSERT_EQ(ACTION_TYPE_ACQUIRE, m_policy->start_action(global_id));
 
   auto instance_id = stringify(m_local_io_ctx.get_instance_id());
-  std::set<std::string> shuffle_global_image_ids;
-  m_policy->add_instances({instance_id}, &shuffle_global_image_ids);
+  image_map::GlobalIds shuffle_global_ids;
+  m_policy->add_instances({instance_id}, &shuffle_global_ids);
 
-  ASSERT_EQ(0U, shuffle_global_image_ids.size());
-  ASSERT_TRUE(m_policy->finish_action(global_image_id, -ENOENT));
+  ASSERT_EQ(0U, shuffle_global_ids.size());
+  ASSERT_TRUE(m_policy->finish_action(global_id, -ENOENT));
 
-  ASSERT_EQ(ACTION_TYPE_RELEASE, m_policy->start_action(global_image_id));
-  ASSERT_TRUE(m_policy->finish_action(global_image_id, 0));
+  ASSERT_EQ(ACTION_TYPE_RELEASE, m_policy->start_action(global_id));
+  ASSERT_TRUE(m_policy->finish_action(global_id, 0));
 
-  ASSERT_EQ(ACTION_TYPE_MAP_UPDATE, m_policy->start_action(global_image_id));
-  ASSERT_TRUE(m_policy->finish_action(global_image_id, 0));
+  ASSERT_EQ(ACTION_TYPE_MAP_UPDATE, m_policy->start_action(global_id));
+  ASSERT_TRUE(m_policy->finish_action(global_id, 0));
 
-  ASSERT_EQ(ACTION_TYPE_ACQUIRE, m_policy->start_action(global_image_id));
-  ASSERT_FALSE(m_policy->finish_action(global_image_id, 0));
+  ASSERT_EQ(ACTION_TYPE_ACQUIRE, m_policy->start_action(global_id));
+  ASSERT_FALSE(m_policy->finish_action(global_id, 0));
 }
 
 } // namespace image_map
diff --git a/src/test/rbd_mirror/pool_watcher/test_mock_RefreshEntitiesRequest.cc b/src/test/rbd_mirror/pool_watcher/test_mock_RefreshEntitiesRequest.cc
new file mode 100644 (file)
index 0000000..bf4e949
--- /dev/null
@@ -0,0 +1,120 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#include "test/rbd_mirror/test_mock_fixture.h"
+#include "test/librados_test_stub/MockTestMemIoCtxImpl.h"
+#include "test/librados_test_stub/MockTestMemRadosClient.h"
+#include "test/librbd/mock/MockImageCtx.h"
+#include "tools/rbd_mirror/pool_watcher/RefreshEntitiesRequest.h"
+#include "include/stringify.h"
+
+namespace librbd {
+namespace {
+
+struct MockTestImageCtx : public librbd::MockImageCtx {
+  explicit MockTestImageCtx(librbd::ImageCtx &image_ctx)
+    : librbd::MockImageCtx(image_ctx) {
+  }
+};
+
+} // anonymous namespace
+} // namespace librbd
+
+// template definitions
+#include "tools/rbd_mirror/pool_watcher/RefreshEntitiesRequest.cc"
+template class rbd::mirror::pool_watcher::RefreshEntitiesRequest<librbd::MockTestImageCtx>;
+
+namespace rbd {
+namespace mirror {
+namespace pool_watcher {
+
+using ::testing::_;
+using ::testing::DoAll;
+using ::testing::InSequence;
+using ::testing::Invoke;
+using ::testing::Return;
+using ::testing::StrEq;
+using ::testing::WithArg;
+
+class TestMockPoolWatcherRefreshEntitiesRequest : public TestMockFixture {
+public:
+  typedef RefreshEntitiesRequest<librbd::MockTestImageCtx> MockRefreshEntitiesRequest;
+
+  void expect_mirror_image_list(librados::IoCtx &io_ctx,
+                                const std::map<std::string, std::string> &ids,
+                                int r) {
+    bufferlist bl;
+    encode(ids, bl);
+
+    EXPECT_CALL(get_mock_io_ctx(io_ctx),
+                exec(RBD_MIRRORING, _, StrEq("rbd"), StrEq("mirror_image_list"),
+                     _, _, _, _))
+      .WillOnce(DoAll(WithArg<5>(Invoke([bl](bufferlist *out_bl) {
+                                          *out_bl = bl;
+                                        })),
+                      Return(r)));
+  }
+
+};
+
+TEST_F(TestMockPoolWatcherRefreshEntitiesRequest, Success) {
+  InSequence seq;
+  expect_mirror_image_list(m_remote_io_ctx, {{"local id", "global id"}}, 0);
+
+  C_SaferCond ctx;
+  std::map<MirrorEntity, std::string> entities;
+  MockRefreshEntitiesRequest *req = new MockRefreshEntitiesRequest(
+    m_remote_io_ctx, &entities, &ctx);
+
+  req->send();
+  ASSERT_EQ(0, ctx.wait());
+
+  std::map<MirrorEntity, std::string> expected_entities =
+    {{{MIRROR_ENTITY_TYPE_IMAGE, "global id", 1}, "local id"}};
+  ASSERT_EQ(expected_entities, entities);
+}
+
+TEST_F(TestMockPoolWatcherRefreshEntitiesRequest, LargeDirectory) {
+  InSequence seq;
+  std::map<std::string, std::string> mirror_list;
+  std::map<MirrorEntity, std::string> expected_entities;
+  for (uint32_t idx = 1; idx <= 1024; ++idx) {
+    mirror_list.insert(std::make_pair("local id " + stringify(idx),
+                                      "global id " + stringify(idx)));
+    expected_entities.insert(
+      {{MIRROR_ENTITY_TYPE_IMAGE, "global id " + stringify(idx), 1},
+       "local id " + stringify(idx)});
+  }
+
+  expect_mirror_image_list(m_remote_io_ctx, mirror_list, 0);
+  expect_mirror_image_list(m_remote_io_ctx, {{"local id", "global id"}}, 0);
+
+  C_SaferCond ctx;
+  std::map<MirrorEntity, std::string> entities;
+  MockRefreshEntitiesRequest *req = new MockRefreshEntitiesRequest(
+    m_remote_io_ctx, &entities, &ctx);
+
+  req->send();
+  ASSERT_EQ(0, ctx.wait());
+
+  expected_entities.insert(
+    {{MIRROR_ENTITY_TYPE_IMAGE, "global id", 1}, "local id"});
+  ASSERT_EQ(expected_entities, entities);
+}
+
+TEST_F(TestMockPoolWatcherRefreshEntitiesRequest, MirrorImageListError) {
+  InSequence seq;
+  expect_mirror_image_list(m_remote_io_ctx, {}, -EINVAL);
+
+  C_SaferCond ctx;
+  std::map<MirrorEntity, std::string> entities;
+  MockRefreshEntitiesRequest *req = new MockRefreshEntitiesRequest(
+    m_remote_io_ctx, &entities, &ctx);
+
+  req->send();
+  ASSERT_EQ(-EINVAL, ctx.wait());
+}
+
+} // namespace pool_watcher
+} // namespace mirror
+} // namespace rbd
diff --git a/src/test/rbd_mirror/pool_watcher/test_mock_RefreshImagesRequest.cc b/src/test/rbd_mirror/pool_watcher/test_mock_RefreshImagesRequest.cc
deleted file mode 100644 (file)
index 3347a6c..0000000
+++ /dev/null
@@ -1,117 +0,0 @@
-// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
-// vim: ts=8 sw=2 smarttab
-
-#include "test/rbd_mirror/test_mock_fixture.h"
-#include "test/librados_test_stub/MockTestMemIoCtxImpl.h"
-#include "test/librados_test_stub/MockTestMemRadosClient.h"
-#include "test/librbd/mock/MockImageCtx.h"
-#include "tools/rbd_mirror/pool_watcher/RefreshImagesRequest.h"
-#include "include/stringify.h"
-
-namespace librbd {
-namespace {
-
-struct MockTestImageCtx : public librbd::MockImageCtx {
-  explicit MockTestImageCtx(librbd::ImageCtx &image_ctx)
-    : librbd::MockImageCtx(image_ctx) {
-  }
-};
-
-} // anonymous namespace
-} // namespace librbd
-
-// template definitions
-#include "tools/rbd_mirror/pool_watcher/RefreshImagesRequest.cc"
-template class rbd::mirror::pool_watcher::RefreshImagesRequest<librbd::MockTestImageCtx>;
-
-namespace rbd {
-namespace mirror {
-namespace pool_watcher {
-
-using ::testing::_;
-using ::testing::DoAll;
-using ::testing::InSequence;
-using ::testing::Invoke;
-using ::testing::Return;
-using ::testing::StrEq;
-using ::testing::WithArg;
-
-class TestMockPoolWatcherRefreshImagesRequest : public TestMockFixture {
-public:
-  typedef RefreshImagesRequest<librbd::MockTestImageCtx> MockRefreshImagesRequest;
-
-  void expect_mirror_image_list(librados::IoCtx &io_ctx,
-                                const std::map<std::string, std::string> &ids,
-                                int r) {
-    bufferlist bl;
-    encode(ids, bl);
-
-    EXPECT_CALL(get_mock_io_ctx(io_ctx),
-                exec(RBD_MIRRORING, _, StrEq("rbd"), StrEq("mirror_image_list"),
-                     _, _, _, _))
-      .WillOnce(DoAll(WithArg<5>(Invoke([bl](bufferlist *out_bl) {
-                                          *out_bl = bl;
-                                        })),
-                      Return(r)));
-  }
-
-};
-
-TEST_F(TestMockPoolWatcherRefreshImagesRequest, Success) {
-  InSequence seq;
-  expect_mirror_image_list(m_remote_io_ctx, {{"local id", "global id"}}, 0);
-
-  C_SaferCond ctx;
-  ImageIds image_ids;
-  MockRefreshImagesRequest *req = new MockRefreshImagesRequest(
-    m_remote_io_ctx, &image_ids, &ctx);
-
-  req->send();
-  ASSERT_EQ(0, ctx.wait());
-
-  ImageIds expected_image_ids = {{"global id", "local id"}};
-  ASSERT_EQ(expected_image_ids, image_ids);
-}
-
-TEST_F(TestMockPoolWatcherRefreshImagesRequest, LargeDirectory) {
-  InSequence seq;
-  std::map<std::string, std::string> mirror_list;
-  ImageIds expected_image_ids;
-  for (uint32_t idx = 1; idx <= 1024; ++idx) {
-    mirror_list.insert(std::make_pair("local id " + stringify(idx),
-                                      "global id " + stringify(idx)));
-    expected_image_ids.insert({{"global id " + stringify(idx),
-                                "local id " + stringify(idx)}});
-  }
-
-  expect_mirror_image_list(m_remote_io_ctx, mirror_list, 0);
-  expect_mirror_image_list(m_remote_io_ctx, {{"local id", "global id"}}, 0);
-
-  C_SaferCond ctx;
-  ImageIds image_ids;
-  MockRefreshImagesRequest *req = new MockRefreshImagesRequest(
-    m_remote_io_ctx, &image_ids, &ctx);
-
-  req->send();
-  ASSERT_EQ(0, ctx.wait());
-
-  expected_image_ids.insert({"global id", "local id"});
-  ASSERT_EQ(expected_image_ids, image_ids);
-}
-
-TEST_F(TestMockPoolWatcherRefreshImagesRequest, MirrorImageListError) {
-  InSequence seq;
-  expect_mirror_image_list(m_remote_io_ctx, {}, -EINVAL);
-
-  C_SaferCond ctx;
-  ImageIds image_ids;
-  MockRefreshImagesRequest *req = new MockRefreshImagesRequest(
-    m_remote_io_ctx, &image_ids, &ctx);
-
-  req->send();
-  ASSERT_EQ(-EINVAL, ctx.wait());
-}
-
-} // namespace pool_watcher
-} // namespace mirror
-} // namespace rbd
index 351bba2175b0501ae898409bb66ce690fb98df9f..5bc5b18085be59121569a92f00b58ab658a276aa 100644 (file)
@@ -32,8 +32,8 @@
 
 using namespace std::chrono_literals;
 
-using rbd::mirror::ImageId;
-using rbd::mirror::ImageIds;
+using rbd::mirror::MirrorEntity;
+using rbd::mirror::MirrorEntities;
 using rbd::mirror::PoolWatcher;
 using rbd::mirror::PeerSpec;
 using rbd::mirror::RadosRef;
@@ -73,19 +73,23 @@ public:
   struct PoolWatcherListener : public rbd::mirror::pool_watcher::Listener {
     TestPoolWatcher *test;
     ceph::condition_variable cond;
-    ImageIds image_ids;
+    set<string> image_ids;
 
     explicit PoolWatcherListener(TestPoolWatcher *test) : test(test) {
     }
 
     void handle_update(const std::string &mirror_uuid,
-                       ImageIds &&added_image_ids,
-                       ImageIds &&removed_image_ids) override {
+                       MirrorEntities &&added_entities,
+                       MirrorEntities &&removed_entities) override {
       std::lock_guard locker{test->m_lock};
-      for (auto &image_id : removed_image_ids) {
-        image_ids.erase(image_id);
+      for (auto &entity : removed_entities) {
+        EXPECT_EQ(entity.type, rbd::mirror::MIRROR_ENTITY_TYPE_IMAGE);
+        image_ids.erase(entity.global_id);
+      }
+      for (auto &entity : added_entities) {
+        EXPECT_EQ(entity.type, rbd::mirror::MIRROR_ENTITY_TYPE_IMAGE);
+        image_ids.insert(entity.global_id);
       }
-      image_ids.insert(added_image_ids.begin(), added_image_ids.end());
       cond.notify_all();
     }
   };
@@ -120,13 +124,6 @@ public:
     m_pool_watcher->init();
   }
 
-  string get_image_id(librados::IoCtx *ioctx, const string &image_name) {
-    string obj = librbd::util::id_obj_name(image_name);
-    string id;
-    EXPECT_EQ(0, librbd::cls_client::get_id(ioctx, obj, &id));
-    return id;
-  }
-
   void create_image(const string &pool_name, bool mirrored=true,
                    string *image_name=nullptr) {
     uint64_t features = librbd::util::get_rbd_default_features(g_ceph_context);
@@ -151,8 +148,7 @@ public:
                                                sizeof(mirror_image_info)));
       image.close();
 
-      m_mirrored_images.insert(ImageId(
-        mirror_image_info.global_id, get_image_id(&ioctx, name)));
+      m_mirrored_images.insert(mirror_image_info.global_id);
     }
     if (image_name != nullptr)
       *image_name = name;
@@ -199,8 +195,7 @@ public:
                                                sizeof(mirror_image_info)));
       image.close();
 
-      m_mirrored_images.insert(ImageId(
-        mirror_image_info.global_id, get_image_id(&cioctx, name)));
+      m_mirrored_images.insert(mirror_image_info.global_id);
     }
     if (image_name != nullptr)
       *image_name = name;
@@ -223,7 +218,7 @@ public:
   std::unique_ptr<PoolWatcher<> > m_pool_watcher;
 
   set<string> m_pools;
-  ImageIds m_mirrored_images;
+  set<string> m_mirrored_images;
 
   uint64_t m_image_number;
   uint64_t m_snap_number;
index ac4ddb7923a4643729ed8465707614201d8ecee6..419969dd6a9b6d146f730ff905550d4691367512 100644 (file)
@@ -53,12 +53,12 @@ namespace image_map {
 
 template <>
 struct LoadRequest<librbd::MockTestImageCtx> {
-  std::map<std::string, cls::rbd::MirrorImageMap> *image_map;
+  std::map<GlobalId, cls::rbd::MirrorImageMap> *image_map;
   Context *on_finish = nullptr;
 
   static LoadRequest *s_instance;
   static LoadRequest *create(librados::IoCtx &ioctx,
-                             std::map<std::string, cls::rbd::MirrorImageMap> *image_map,
+                             std::map<GlobalId, cls::rbd::MirrorImageMap> *image_map,
                              Context *on_finish) {
     ceph_assert(s_instance != nullptr);
     s_instance->image_map = image_map;
@@ -78,8 +78,8 @@ struct UpdateRequest<librbd::MockTestImageCtx> {
   Context *on_finish = nullptr;
   static UpdateRequest *s_instance;
   static UpdateRequest *create(librados::IoCtx &ioctx,
-                               std::map<std::string, cls::rbd::MirrorImageMap> &&update_mapping,
-                               std::set<std::string> &&global_image_ids,
+                               std::map<GlobalId, cls::rbd::MirrorImageMap> &&update_mapping,
+                               GlobalIds &&removed_global_ids,
                                Context *on_finish) {
     ceph_assert(s_instance != nullptr);
     s_instance->on_finish = on_finish;
@@ -420,6 +420,14 @@ public:
     }
   }
 
+  MirrorEntities make_image_entities(const std::set<std::string> &global_image_ids) {
+    MirrorEntities entities;
+    for (auto &global_image_id : global_image_ids) {
+      entities.emplace(MIRROR_ENTITY_TYPE_IMAGE, global_image_id, 1);
+    }
+    return entities;
+  }
+
   ceph::mutex m_lock = ceph::make_mutex("TestMockImageMap::m_lock");
   ceph::condition_variable m_cond;
   uint32_t m_notify_update_count = 0;
@@ -449,7 +457,6 @@ TEST_F(TestMockImageMap, SetLocalImages) {
   std::set<std::string> global_image_ids{
     "global id 1", "global id 2"
   };
-  std::set<std::string> global_image_ids_ack(global_image_ids);
 
   // UPDATE_MAPPING+ACQUIRE
   expect_add_event(mock_threads);
@@ -460,13 +467,14 @@ TEST_F(TestMockImageMap, SetLocalImages) {
   listener_acquire_images(mock_listener, global_image_ids, &peer_ack_ctxs);
 
   // initial image list
-  mock_image_map->update_images("", std::move(global_image_ids), {});
+  auto entities = make_image_entities(global_image_ids);
+  mock_image_map->update_images("", std::move(entities), {});
 
   ASSERT_TRUE(wait_for_map_update(1));
-  ASSERT_TRUE(wait_for_listener_notify(global_image_ids_ack.size()));
+  ASSERT_TRUE(wait_for_listener_notify(global_image_ids.size()));
 
   // remote peer ACKs image acquire request
-  remote_peer_ack_nowait(mock_image_map.get(), global_image_ids_ack, 0,
+  remote_peer_ack_nowait(mock_image_map.get(), global_image_ids, 0,
                          &peer_ack_ctxs);
 
   wait_for_scheduled_task();
@@ -495,12 +503,9 @@ TEST_F(TestMockImageMap, AddRemoveLocalImage) {
   std::set<std::string> initial_global_image_ids{
     "global id 1", "global id 2"
   };
-  std::set<std::string> initial_global_image_ids_ack(initial_global_image_ids);
-
   std::set<std::string> remove_global_image_ids{
     "global id 1", "global id 2"
   };
-  std::set<std::string> remove_global_image_ids_ack(remove_global_image_ids);
 
   // UPDATE_MAPPING+ACQUIRE
   expect_add_event(mock_threads);
@@ -512,13 +517,14 @@ TEST_F(TestMockImageMap, AddRemoveLocalImage) {
                           &peer_ack_ctxs);
 
   // initial image list
-  mock_image_map->update_images("", std::move(initial_global_image_ids), {});
+  auto entities = make_image_entities(initial_global_image_ids);
+  mock_image_map->update_images("", std::move(entities), {});
 
   ASSERT_TRUE(wait_for_map_update(1));
-  ASSERT_TRUE(wait_for_listener_notify(initial_global_image_ids_ack.size()));
+  ASSERT_TRUE(wait_for_listener_notify(initial_global_image_ids.size()));
 
   // remote peer ACKs image acquire request
-  remote_peer_ack_nowait(mock_image_map.get(), initial_global_image_ids_ack, 0,
+  remote_peer_ack_nowait(mock_image_map.get(), initial_global_image_ids, 0,
                          &peer_ack_ctxs);
 
   // RELEASE+REMOVE_MAPPING
@@ -529,10 +535,11 @@ TEST_F(TestMockImageMap, AddRemoveLocalImage) {
                      0);
 
   // remove images
-  mock_image_map->update_images("", {}, std::move(remove_global_image_ids));
-  ASSERT_TRUE(wait_for_listener_notify(remove_global_image_ids_ack.size()));
+  entities = make_image_entities(remove_global_image_ids);
+  mock_image_map->update_images("", {}, std::move(entities));
+  ASSERT_TRUE(wait_for_listener_notify(remove_global_image_ids.size()));
 
-  remote_peer_ack_wait(mock_image_map.get(), remove_global_image_ids_ack, 0,
+  remote_peer_ack_wait(mock_image_map.get(), remove_global_image_ids, 0,
                        &peer_ack_ctxs);
 
   wait_for_scheduled_task();
@@ -561,12 +568,9 @@ TEST_F(TestMockImageMap, AddRemoveRemoteImage) {
   std::set<std::string> initial_global_image_ids{
     "global id 1", "global id 2"
   };
-  std::set<std::string> initial_global_image_ids_ack(initial_global_image_ids);
-
   std::set<std::string> remove_global_image_ids{
     "global id 1", "global id 2"
   };
-  std::set<std::string> remove_global_image_ids_ack(remove_global_image_ids);
 
   // UPDATE_MAPPING+ACQUIRE
   expect_add_event(mock_threads);
@@ -578,14 +582,14 @@ TEST_F(TestMockImageMap, AddRemoveRemoteImage) {
                           &peer_ack_ctxs);
 
   // initial image list
-  mock_image_map->update_images("uuid1", std::move(initial_global_image_ids),
-                                {});
+  auto entities = make_image_entities(initial_global_image_ids);
+  mock_image_map->update_images("uuid1", std::move(entities), {});
 
   ASSERT_TRUE(wait_for_map_update(1));
-  ASSERT_TRUE(wait_for_listener_notify(initial_global_image_ids_ack.size()));
+  ASSERT_TRUE(wait_for_listener_notify(initial_global_image_ids.size()));
 
   // remote peer ACKs image acquire request
-  remote_peer_ack_nowait(mock_image_map.get(), initial_global_image_ids_ack, 0,
+  remote_peer_ack_nowait(mock_image_map.get(), initial_global_image_ids, 0,
                          &peer_ack_ctxs);
 
   // RELEASE+REMOVE_MAPPING
@@ -599,12 +603,13 @@ TEST_F(TestMockImageMap, AddRemoveRemoteImage) {
                      0);
 
   // remove images
-  mock_image_map->update_images("uuid1", {}, std::move(remove_global_image_ids));
-  ASSERT_TRUE(wait_for_listener_notify(remove_global_image_ids_ack.size() * 2));
+  entities = make_image_entities(remove_global_image_ids);
+  mock_image_map->update_images("uuid1", {}, std::move(entities));
+  ASSERT_TRUE(wait_for_listener_notify(remove_global_image_ids.size() * 2));
 
-  remote_peer_ack_nowait(mock_image_map.get(), remove_global_image_ids_ack, 0,
+  remote_peer_ack_nowait(mock_image_map.get(), remove_global_image_ids, 0,
                          &peer_remove_ack_ctxs);
-  remote_peer_ack_wait(mock_image_map.get(), remove_global_image_ids_ack, 0,
+  remote_peer_ack_wait(mock_image_map.get(), remove_global_image_ids, 0,
                        &peer_ack_ctxs);
 
   wait_for_scheduled_task();
@@ -633,14 +638,10 @@ TEST_F(TestMockImageMap, AddRemoveRemoteImageDuplicateNotification) {
   std::set<std::string> initial_global_image_ids{
     "global id 1", "global id 2"
   };
-  std::set<std::string> initial_global_image_ids_dup(initial_global_image_ids);
-  std::set<std::string> initial_global_image_ids_ack(initial_global_image_ids);
 
   std::set<std::string> remove_global_image_ids{
     "global id 1", "global id 2"
   };
-  std::set<std::string> remove_global_image_ids_dup(remove_global_image_ids);
-  std::set<std::string> remove_global_image_ids_ack(remove_global_image_ids);
 
   // UPDATE_MAPPING+ACQUIRE
   expect_add_event(mock_threads);
@@ -652,17 +653,19 @@ TEST_F(TestMockImageMap, AddRemoveRemoteImageDuplicateNotification) {
                           &peer_ack_ctxs);
 
   // initial image list
-  mock_image_map->update_images("uuid1", std::move(initial_global_image_ids), {});
+  auto entities = make_image_entities(initial_global_image_ids);
+  mock_image_map->update_images("uuid1", std::move(entities), {});
 
   ASSERT_TRUE(wait_for_map_update(1));
-  ASSERT_TRUE(wait_for_listener_notify(initial_global_image_ids_ack.size()));
+  ASSERT_TRUE(wait_for_listener_notify(initial_global_image_ids.size()));
 
   // trigger duplicate "add" event
   wait_for_scheduled_task();
-  mock_image_map->update_images("uuid1", std::move(initial_global_image_ids_dup), {});
+  entities = make_image_entities(initial_global_image_ids);
+  mock_image_map->update_images("uuid1", std::move(entities), {});
 
   // remote peer ACKs image acquire request
-  remote_peer_ack_nowait(mock_image_map.get(), initial_global_image_ids_ack, 0,
+  remote_peer_ack_nowait(mock_image_map.get(), initial_global_image_ids, 0,
                          &peer_ack_ctxs);
 
   // RELEASE+REMOVE_MAPPING
@@ -675,16 +678,18 @@ TEST_F(TestMockImageMap, AddRemoveRemoteImageDuplicateNotification) {
   update_map_request(mock_threads, mock_update_request, remove_global_image_ids, 0);
 
   // remove images
-  mock_image_map->update_images("uuid1", {}, std::move(remove_global_image_ids));
-  ASSERT_TRUE(wait_for_listener_notify(remove_global_image_ids_ack.size() * 2));
+  entities = make_image_entities(remove_global_image_ids);
+  mock_image_map->update_images("uuid1", {}, std::move(entities));
+  ASSERT_TRUE(wait_for_listener_notify(remove_global_image_ids.size() * 2));
 
-  remote_peer_ack_nowait(mock_image_map.get(), remove_global_image_ids_ack, 0,
+  remote_peer_ack_nowait(mock_image_map.get(), remove_global_image_ids, 0,
                          &peer_remove_ack_ctxs);
-  remote_peer_ack_wait(mock_image_map.get(), remove_global_image_ids_ack, 0,
+  remote_peer_ack_wait(mock_image_map.get(), remove_global_image_ids, 0,
                        &peer_ack_ctxs);
 
   // trigger duplicate "remove" notification
-  mock_image_map->update_images("uuid1", {}, std::move(remove_global_image_ids_dup));
+  entities = make_image_entities(remove_global_image_ids);
+  mock_image_map->update_images("uuid1", {}, std::move(entities));
 
   wait_for_scheduled_task();
   ASSERT_EQ(0, when_shut_down(mock_image_map.get()));
@@ -712,7 +717,6 @@ TEST_F(TestMockImageMap, AcquireImageErrorRetry) {
   std::set<std::string> initial_global_image_ids{
     "global id 1", "global id 2"
   };
-  std::set<std::string> initial_global_image_ids_ack(initial_global_image_ids);
 
   // UPDATE_MAPPING failure
   expect_add_event(mock_threads);
@@ -728,13 +732,14 @@ TEST_F(TestMockImageMap, AcquireImageErrorRetry) {
                           &peer_ack_ctxs);
 
   // initial image list
-  mock_image_map->update_images("uuid1", std::move(initial_global_image_ids), {});
+  auto entities = make_image_entities(initial_global_image_ids);
+  mock_image_map->update_images("uuid1", std::move(entities), {});
 
   ASSERT_TRUE(wait_for_map_update(1));
-  ASSERT_TRUE(wait_for_listener_notify(initial_global_image_ids_ack.size()));
+  ASSERT_TRUE(wait_for_listener_notify(initial_global_image_ids.size()));
 
   // remote peer ACKs image acquire request
-  remote_peer_ack_nowait(mock_image_map.get(), initial_global_image_ids_ack, 0,
+  remote_peer_ack_nowait(mock_image_map.get(), initial_global_image_ids, 0,
                          &peer_ack_ctxs);
 
   wait_for_scheduled_task();
@@ -764,7 +769,6 @@ TEST_F(TestMockImageMap, RemoveRemoteAndLocalImage) {
   std::set<std::string> initial_remote_global_image_ids{
     "global id 1"
   };
-  std::set<std::string> initial_remote_global_image_ids_ack(initial_remote_global_image_ids);
 
   // local image set
   std::set<std::string> initial_local_global_image_ids{
@@ -775,12 +779,9 @@ TEST_F(TestMockImageMap, RemoveRemoteAndLocalImage) {
   std::set<std::string> remote_remove_global_image_ids{
     "global id 1"
   };
-  std::set<std::string> remote_remove_global_image_ids_ack(remote_remove_global_image_ids);
-
   std::set<std::string> local_remove_global_image_ids{
     "global id 1"
   };
-  std::set<std::string> local_remove_global_image_ids_ack(local_remove_global_image_ids);
 
   // UPDATE_MAPPING+ACQUIRE
   expect_add_event(mock_threads);
@@ -792,18 +793,19 @@ TEST_F(TestMockImageMap, RemoveRemoteAndLocalImage) {
                           &peer_ack_ctxs);
 
   // initial remote image list
-  mock_image_map->update_images("uuid1", std::move(initial_remote_global_image_ids), {});
+  auto entities = make_image_entities(initial_remote_global_image_ids);
+  mock_image_map->update_images("uuid1", std::move(entities), {});
 
   ASSERT_TRUE(wait_for_map_update(1));
-  ASSERT_TRUE(wait_for_listener_notify(initial_remote_global_image_ids_ack.size()));
+  ASSERT_TRUE(wait_for_listener_notify(initial_remote_global_image_ids.size()));
 
   // remote peer ACKs image acquire request
-  remote_peer_ack_nowait(mock_image_map.get(),
-                         initial_remote_global_image_ids_ack, 0,
-                         &peer_ack_ctxs);
+  remote_peer_ack_nowait(mock_image_map.get(), initial_remote_global_image_ids,
+                         0, &peer_ack_ctxs);
 
   // set initial local image list -- this is a no-op from policy pov
-  mock_image_map->update_images("", std::move(initial_local_global_image_ids), {});
+  entities = make_image_entities(initial_local_global_image_ids);
+  mock_image_map->update_images("", std::move(entities), {});
 
   // remove remote images -- this should be a no-op from policy pov
   // except the listener notification
@@ -811,8 +813,9 @@ TEST_F(TestMockImageMap, RemoveRemoteAndLocalImage) {
   listener_remove_images(mock_listener, "uuid1", remote_remove_global_image_ids,
                          &peer_ack_remove_ctxs);
 
-  mock_image_map->update_images("uuid1", {}, std::move(remote_remove_global_image_ids));
-  ASSERT_TRUE(wait_for_listener_notify(remote_remove_global_image_ids_ack.size()));
+  entities = make_image_entities(remote_remove_global_image_ids);
+  mock_image_map->update_images("uuid1", {}, std::move(entities));
+  ASSERT_TRUE(wait_for_listener_notify(remote_remove_global_image_ids.size()));
 
   // RELEASE+REMOVE_MAPPING
   expect_add_event(mock_threads);
@@ -821,12 +824,13 @@ TEST_F(TestMockImageMap, RemoveRemoteAndLocalImage) {
   update_map_request(mock_threads, mock_update_request, local_remove_global_image_ids, 0);
 
   // remove local images
-  mock_image_map->update_images("", {}, std::move(local_remove_global_image_ids));
-  ASSERT_TRUE(wait_for_listener_notify(local_remove_global_image_ids_ack.size()));
+  entities = make_image_entities(local_remove_global_image_ids);
+  mock_image_map->update_images("", {}, std::move(entities));
+  ASSERT_TRUE(wait_for_listener_notify(local_remove_global_image_ids.size()));
 
-  remote_peer_ack_nowait(mock_image_map.get(), local_remove_global_image_ids_ack,
+  remote_peer_ack_nowait(mock_image_map.get(), local_remove_global_image_ids,
                          0,  &peer_ack_remove_ctxs);
-  remote_peer_ack_wait(mock_image_map.get(), local_remove_global_image_ids_ack,
+  remote_peer_ack_wait(mock_image_map.get(), local_remove_global_image_ids,
                        0, &peer_ack_ctxs);
 
   wait_for_scheduled_task();
@@ -855,7 +859,6 @@ TEST_F(TestMockImageMap, AddInstance) {
   std::set<std::string> global_image_ids{
     "global id 1", "global id 2", "global id 3", "global id 4", "global id 5"
   };
-  std::set<std::string> global_image_ids_ack(global_image_ids);
 
   // UPDATE_MAPPING+ACQUIRE
   expect_add_event(mock_threads);
@@ -867,13 +870,14 @@ TEST_F(TestMockImageMap, AddInstance) {
                           &peer_ack_ctxs);
 
   // initial image list
-  mock_image_map->update_images("uuid1", std::move(global_image_ids), {});
+  auto entities = make_image_entities(global_image_ids);
+  mock_image_map->update_images("uuid1", std::move(entities), {});
 
   ASSERT_TRUE(wait_for_map_update(1));
-  ASSERT_TRUE(wait_for_listener_notify(global_image_ids_ack.size()));
+  ASSERT_TRUE(wait_for_listener_notify(global_image_ids.size()));
 
   // remote peer ACKs image acquire request
-  remote_peer_ack_nowait(mock_image_map.get(), global_image_ids_ack, 0,
+  remote_peer_ack_nowait(mock_image_map.get(), global_image_ids, 0,
                          &peer_ack_ctxs);
   wait_for_scheduled_task();
 
@@ -927,7 +931,6 @@ TEST_F(TestMockImageMap, RemoveInstance) {
   std::set<std::string> global_image_ids{
     "global id 1", "global id 2", "global id 3", "global id 4", "global id 5"
   };
-  std::set<std::string> global_image_ids_ack(global_image_ids);
 
   expect_add_event(mock_threads);
 
@@ -940,13 +943,14 @@ TEST_F(TestMockImageMap, RemoveInstance) {
                           &peer_ack_ctxs);
 
   // set initial image list
-  mock_image_map->update_images("uuid1", std::move(global_image_ids), {});
+  auto entities = make_image_entities(global_image_ids);
+  mock_image_map->update_images("uuid1", std::move(entities), {});
 
   ASSERT_TRUE(wait_for_map_update(1));
-  ASSERT_TRUE(wait_for_listener_notify(global_image_ids_ack.size()));
+  ASSERT_TRUE(wait_for_listener_notify(global_image_ids.size()));
 
   // remote peer ACKs image acquire request -- completing action
-  remote_peer_ack_nowait(mock_image_map.get(), global_image_ids_ack, 0,
+  remote_peer_ack_nowait(mock_image_map.get(), global_image_ids, 0,
                          &peer_ack_ctxs);
   wait_for_scheduled_task();
 
@@ -1015,9 +1019,13 @@ TEST_F(TestMockImageMap, AddInstancePingPongImageTest) {
     "global id 11", "global id 12", "global id 13", "global id 14"
   };
 
-  std::map<std::string, cls::rbd::MirrorImageMap> image_mapping;
+  std::map<GlobalId, cls::rbd::MirrorImageMap> image_mapping;
+  bufferlist bl;
+  image_map::PolicyMetaNone policy_meta;
+  encode(image_map::PolicyData(1, policy_meta), bl);
   for (auto& global_image_id : global_image_ids) {
-    image_mapping[global_image_id] = {m_local_instance_id, {}, {}};
+    GlobalId global_id{MIRROR_ENTITY_TYPE_IMAGE, global_image_id};
+    image_mapping[global_id] = {m_local_instance_id, {}, bl};
   }
 
   // ACQUIRE
@@ -1044,11 +1052,9 @@ TEST_F(TestMockImageMap, AddInstancePingPongImageTest) {
 
   mock_image_map->update_instances_added({m_local_instance_id});
 
-  std::set<std::string> global_image_ids_ack(global_image_ids);
-
   // remote peer ACKs image acquire request -- completing action
-  ASSERT_TRUE(wait_for_listener_notify(global_image_ids_ack.size()));
-  remote_peer_ack_nowait(mock_image_map.get(), global_image_ids_ack, 0,
+  ASSERT_TRUE(wait_for_listener_notify(global_image_ids.size()));
+  remote_peer_ack_nowait(mock_image_map.get(), global_image_ids, 0,
                          &peer_ack_ctxs);
   wait_for_scheduled_task();
 
@@ -1061,13 +1067,14 @@ TEST_F(TestMockImageMap, AddInstancePingPongImageTest) {
                           &peer_ack_ctxs);
 
   // set initial image list
-  mock_image_map->update_images("uuid1", std::move(global_image_ids), {});
+  auto entities = make_image_entities(global_image_ids);
+  mock_image_map->update_images("uuid1", std::move(entities), {});
 
   ASSERT_TRUE(wait_for_map_update(1));
-  ASSERT_TRUE(wait_for_listener_notify(global_image_ids_ack.size()));
+  ASSERT_TRUE(wait_for_listener_notify(global_image_ids.size()));
 
   // remote peer ACKs image acquire request -- completing action
-  remote_peer_ack_nowait(mock_image_map.get(), global_image_ids_ack, 0,
+  remote_peer_ack_nowait(mock_image_map.get(), global_image_ids, 0,
                          &peer_ack_ctxs);
   wait_for_scheduled_task();
 
@@ -1151,12 +1158,6 @@ TEST_F(TestMockImageMap, RemoveInstanceWithRemoveImage) {
   std::set<std::string> global_image_ids{
     "global id 1", "global id 2", "global id 3", "remote id 4",
   };
-  std::set<std::string> global_image_ids_ack(global_image_ids);
-
-  std::set<std::string> remove_global_image_ids{
-    "global id 1"
-  };
-  std::set<std::string> remove_global_image_ids_ack(remove_global_image_ids);
 
   expect_add_event(mock_threads);
   // UPDATE_MAPPING+ACQUIRE
@@ -1168,12 +1169,13 @@ TEST_F(TestMockImageMap, RemoveInstanceWithRemoveImage) {
                           &peer_ack_ctxs);
 
   // initial image list
-  mock_image_map->update_images("uuid1", std::move(global_image_ids), {});
+  auto entities = make_image_entities(global_image_ids);
+  mock_image_map->update_images("uuid1", std::move(entities), {});
 
   ASSERT_TRUE(wait_for_map_update(1));
-  ASSERT_TRUE(wait_for_listener_notify(global_image_ids_ack.size()));
+  ASSERT_TRUE(wait_for_listener_notify(global_image_ids.size()));
 
-  remote_peer_ack_nowait(mock_image_map.get(), global_image_ids_ack, 0,
+  remote_peer_ack_nowait(mock_image_map.get(), global_image_ids, 0,
                          &peer_ack_ctxs);
   wait_for_scheduled_task();
 
@@ -1202,8 +1204,6 @@ TEST_F(TestMockImageMap, RemoveInstanceWithRemoveImage) {
                          &peer_ack_ctxs);
   wait_for_scheduled_task();
 
-  std::set<std::string> shuffled_global_image_ids_ack(shuffled_global_image_ids);
-
   // RELEASE
 
   std::map<std::string, Context*> peer_ack_remove_ctxs;
@@ -1217,8 +1217,9 @@ TEST_F(TestMockImageMap, RemoveInstanceWithRemoveImage) {
   expect_add_event(mock_threads);
   expect_update_request(mock_update_request, 0);
 
-  mock_image_map->update_images("uuid1", {}, std::move(shuffled_global_image_ids));
-  ASSERT_TRUE(wait_for_listener_notify(shuffled_global_image_ids_ack.size() * 2));
+  entities = make_image_entities(shuffled_global_image_ids);
+  mock_image_map->update_images("uuid1", {}, std::move(entities));
+  ASSERT_TRUE(wait_for_listener_notify(shuffled_global_image_ids.size() * 2));
 
   // instance failed -- update policy for instance removal
   mock_image_map->update_instances_removed({"9876"});
@@ -1256,7 +1257,6 @@ TEST_F(TestMockImageMap, AddErrorAndRemoveImage) {
   std::set<std::string> global_image_ids{
     "global id 1", "global id 2", "global id 3", "remote id 4",
   };
-  std::set<std::string> global_image_ids_ack(global_image_ids);
 
   // UPDATE_MAPPING+ACQUIRE
   expect_add_event(mock_threads);
@@ -1268,13 +1268,14 @@ TEST_F(TestMockImageMap, AddErrorAndRemoveImage) {
                           &peer_ack_ctxs);
 
   // initial image list
-  mock_image_map->update_images("uuid1", std::move(global_image_ids), {});
+  auto entities = make_image_entities(global_image_ids);
+  mock_image_map->update_images("uuid1", std::move(entities), {});
 
   ASSERT_TRUE(wait_for_map_update(1));
-  ASSERT_TRUE(wait_for_listener_notify(global_image_ids_ack.size()));
+  ASSERT_TRUE(wait_for_listener_notify(global_image_ids.size()));
 
   // remote peer ACKs image acquire request
-  remote_peer_ack_nowait(mock_image_map.get(), global_image_ids_ack, 0,
+  remote_peer_ack_nowait(mock_image_map.get(), global_image_ids, 0,
                          &peer_ack_ctxs);
   wait_for_scheduled_task();
 
@@ -1328,8 +1329,6 @@ TEST_F(TestMockImageMap, AddErrorAndRemoveImage) {
                          &remap_peer_ack_ctxs);
   wait_for_scheduled_task();
 
-  std::set<std::string> shuffled_global_image_ids_ack(shuffled_global_image_ids);
-
   // remove image
   std::map<std::string, Context*> peer_ack_remove_ctxs;
   listener_remove_images(mock_listener, "uuid1", shuffled_global_image_ids,
@@ -1339,12 +1338,13 @@ TEST_F(TestMockImageMap, AddErrorAndRemoveImage) {
                           &peer_ack_ctxs);
   update_map_request(mock_threads, mock_update_request, shuffled_global_image_ids, 0);
 
-  mock_image_map->update_images("uuid1", {}, std::move(shuffled_global_image_ids));
-  ASSERT_TRUE(wait_for_listener_notify(shuffled_global_image_ids_ack.size() * 2));
+  entities = make_image_entities(shuffled_global_image_ids);
+  mock_image_map->update_images("uuid1", {}, std::move(entities));
+  ASSERT_TRUE(wait_for_listener_notify(shuffled_global_image_ids.size() * 2));
 
-  remote_peer_ack_nowait(mock_image_map.get(), shuffled_global_image_ids_ack, 0,
+  remote_peer_ack_nowait(mock_image_map.get(), shuffled_global_image_ids, 0,
                          &peer_ack_remove_ctxs);
-  remote_peer_ack_wait(mock_image_map.get(), shuffled_global_image_ids_ack, 0,
+  remote_peer_ack_wait(mock_image_map.get(), shuffled_global_image_ids, 0,
                        &peer_ack_ctxs);
 
   wait_for_scheduled_task();
@@ -1374,18 +1374,15 @@ TEST_F(TestMockImageMap, MirrorUUIDUpdated) {
   std::set<std::string> initial_remote_global_image_ids{
     "global id 1", "global id 2", "global id 3"
   };
-  std::set<std::string> initial_remote_global_image_ids_ack(initial_remote_global_image_ids);
 
   // remote/local images to remove
   std::set<std::string> remote_removed_global_image_ids{
     "global id 1", "global id 2", "global id 3"
   };
-  std::set<std::string> remote_removed_global_image_ids_ack(remote_removed_global_image_ids);
 
   std::set<std::string> remote_added_global_image_ids{
     "global id 1", "global id 2", "global id 3"
   };
-  std::set<std::string> remote_added_global_image_ids_ack(remote_added_global_image_ids);
 
   // UPDATE_MAPPING+ACQUIRE
   expect_add_event(mock_threads);
@@ -1397,14 +1394,15 @@ TEST_F(TestMockImageMap, MirrorUUIDUpdated) {
                           &peer_ack_ctxs);
 
   // initial remote image list
-  mock_image_map->update_images("uuid1", std::move(initial_remote_global_image_ids), {});
+  auto entities = make_image_entities(initial_remote_global_image_ids);
+  mock_image_map->update_images("uuid1", std::move(entities), {});
 
   ASSERT_TRUE(wait_for_map_update(1));
-  ASSERT_TRUE(wait_for_listener_notify(initial_remote_global_image_ids_ack.size()));
+  ASSERT_TRUE(wait_for_listener_notify(initial_remote_global_image_ids.size()));
 
   // remote peer ACKs image acquire request
   remote_peer_ack_nowait(mock_image_map.get(),
-                         initial_remote_global_image_ids_ack, 0,
+                         initial_remote_global_image_ids, 0,
                          &peer_ack_ctxs);
   wait_for_scheduled_task();
 
@@ -1417,14 +1415,15 @@ TEST_F(TestMockImageMap, MirrorUUIDUpdated) {
                           &peer_ack_ctxs);
   update_map_request(mock_threads, mock_update_request, remote_removed_global_image_ids, 0);
 
-  mock_image_map->update_images("uuid1", {}, std::move(remote_removed_global_image_ids));
-  ASSERT_TRUE(wait_for_listener_notify(remote_removed_global_image_ids_ack.size() * 2));
+  entities = make_image_entities(remote_removed_global_image_ids);
+  mock_image_map->update_images("uuid1", {}, std::move(entities));
+  ASSERT_TRUE(wait_for_listener_notify(remote_removed_global_image_ids.size() * 2));
 
   remote_peer_ack_nowait(mock_image_map.get(),
-                         remote_removed_global_image_ids_ack, 0,
+                         remote_removed_global_image_ids, 0,
                          &peer_remove_ack_ctxs);
   remote_peer_ack_wait(mock_image_map.get(),
-                       remote_removed_global_image_ids_ack, 0,
+                       remote_removed_global_image_ids, 0,
                        &peer_ack_ctxs);
 
   // UPDATE_MAPPING+ACQUIRE
@@ -1434,14 +1433,14 @@ TEST_F(TestMockImageMap, MirrorUUIDUpdated) {
   listener_acquire_images(mock_listener, remote_added_global_image_ids,
                           &peer_ack_ctxs);
 
-  mock_image_map->update_images("uuid2", std::move(remote_added_global_image_ids), {});
+  entities = make_image_entities(remote_added_global_image_ids);
+  mock_image_map->update_images("uuid2", std::move(entities), {});
 
   ASSERT_TRUE(wait_for_map_update(1));
-  ASSERT_TRUE(wait_for_listener_notify(remote_added_global_image_ids_ack.size()));
+  ASSERT_TRUE(wait_for_listener_notify(remote_added_global_image_ids.size()));
 
   // remote peer ACKs image acquire request
-  remote_peer_ack_nowait(mock_image_map.get(),
-                         remote_added_global_image_ids_ack, 0,
+  remote_peer_ack_nowait(mock_image_map.get(), remote_added_global_image_ids, 0,
                          &peer_ack_ctxs);
 
   wait_for_scheduled_task();
@@ -1471,7 +1470,6 @@ TEST_F(TestMockImageMap, RebalanceImageMap) {
     "global id 1", "global id 2", "global id 3", "global id 4", "global id 5",
     "global id 6", "global id 7", "global id 8", "global id 9", "global id 10",
   };
-  std::set<std::string> global_image_ids_ack(global_image_ids);
 
   // UPDATE_MAPPING+ACQUIRE
   expect_add_event(mock_threads);
@@ -1483,13 +1481,14 @@ TEST_F(TestMockImageMap, RebalanceImageMap) {
                           &peer_ack_ctxs);
 
   // initial image list
-  mock_image_map->update_images("", std::move(global_image_ids), {});
+  auto entities = make_image_entities(global_image_ids);
+  mock_image_map->update_images("", std::move(entities), {});
 
   ASSERT_TRUE(wait_for_map_update(1));
-  ASSERT_TRUE(wait_for_listener_notify(global_image_ids_ack.size()));
+  ASSERT_TRUE(wait_for_listener_notify(global_image_ids.size()));
 
   // remote peer ACKs image acquire request
-  remote_peer_ack_nowait(mock_image_map.get(), global_image_ids_ack, 0,
+  remote_peer_ack_nowait(mock_image_map.get(), global_image_ids, 0,
                          &peer_ack_ctxs);
   wait_for_scheduled_task();
 
@@ -1520,7 +1519,6 @@ TEST_F(TestMockImageMap, RebalanceImageMap) {
   wait_for_scheduled_task();
 
   // remove all shuffled images -- make way for rebalance
-  std::set<std::string> shuffled_global_image_ids_ack(shuffled_global_image_ids);
 
   // RELEASE+REMOVE_MAPPING
   expect_add_event(mock_threads);
@@ -1529,20 +1527,19 @@ TEST_F(TestMockImageMap, RebalanceImageMap) {
   update_map_request(mock_threads, mock_update_request, shuffled_global_image_ids,
                      0);
 
-  mock_image_map->update_images("", {}, std::move(shuffled_global_image_ids));
-  ASSERT_TRUE(wait_for_listener_notify(shuffled_global_image_ids_ack.size()));
+  entities = make_image_entities(shuffled_global_image_ids);
+  mock_image_map->update_images("", {}, std::move(entities));
+  ASSERT_TRUE(wait_for_listener_notify(shuffled_global_image_ids.size()));
 
-  remote_peer_ack_wait(mock_image_map.get(), shuffled_global_image_ids_ack, 0,
+  remote_peer_ack_wait(mock_image_map.get(), shuffled_global_image_ids, 0,
                        &peer_ack_ctxs);
   wait_for_scheduled_task();
 
   shuffled_global_image_ids.clear();
-  shuffled_global_image_ids_ack.clear();
 
   std::set<std::string> new_global_image_ids = {
     "global id 11"
   };
-  std::set<std::string> new_global_image_ids_ack(new_global_image_ids);
 
   expect_add_event(mock_threads);
   expect_update_request(mock_update_request, 0);
@@ -1555,15 +1552,16 @@ TEST_F(TestMockImageMap, RebalanceImageMap) {
   expect_listener_images_unmapped(mock_listener, 2, &shuffled_global_image_ids,
                                   &peer_ack_ctxs);
 
-  mock_image_map->update_images("", std::move(new_global_image_ids), {});
+  entities = make_image_entities(new_global_image_ids);
+  mock_image_map->update_images("", std::move(entities), {});
 
   ASSERT_TRUE(wait_for_map_update(1));
-  ASSERT_TRUE(wait_for_listener_notify(new_global_image_ids_ack.size()));
+  ASSERT_TRUE(wait_for_listener_notify(new_global_image_ids.size()));
 
   // set rebalance interval
   CephContext *cct = reinterpret_cast<CephContext *>(m_local_io_ctx.cct());
   cct->_conf.set_val("rbd_mirror_image_policy_rebalance_timeout", "5");
-  remote_peer_ack_nowait(mock_image_map.get(), new_global_image_ids_ack, 0,
+  remote_peer_ack_nowait(mock_image_map.get(), new_global_image_ids, 0,
                          &peer_ack_ctxs);
 
   wait_for_scheduled_task();
index 52aefa90a8b7b2c25216d2efd1eb22405c91485d..95dc69353001d867da96de83c3d8e2ff4790af09 100644 (file)
@@ -75,11 +75,11 @@ struct ImageMap<librbd::MockTestImageCtx> {
   MOCK_METHOD1(update_instances_removed, void(const std::vector<std::string>&));
 
   MOCK_METHOD3(update_images_mock, void(const std::string&,
-                                        const std::set<std::string>&,
-                                        const std::set<std::string>&));
+                                        const MirrorEntities&,
+                                        const MirrorEntities&));
   void update_images(const std::string& mirror_uuid,
-                     std::set<std::string>&& added,
-                     std::set<std::string>&& removed) {
+                     MirrorEntities &&added,
+                     MirrorEntities &&removed) {
     update_images_mock(mirror_uuid, added, removed);
   }
 
index 8653a412f5db053c186c451a2c66350054d08477..9c3f1a5f9f842a78a0a1d7b4d0e3043816517b93 100644 (file)
@@ -10,7 +10,7 @@
 #include "librbd/MirroringWatcher.h"
 #include "tools/rbd_mirror/Threads.h"
 #include "tools/rbd_mirror/PoolWatcher.h"
-#include "tools/rbd_mirror/pool_watcher/RefreshImagesRequest.h"
+#include "tools/rbd_mirror/pool_watcher/RefreshEntitiesRequest.h"
 #include "include/stringify.h"
 
 using namespace std::chrono_literals;
@@ -113,27 +113,27 @@ struct Threads<librbd::MockTestImageCtx> {
 namespace pool_watcher {
 
 template <>
-struct RefreshImagesRequest<librbd::MockTestImageCtx> {
-  ImageIds *image_ids = nullptr;
+struct RefreshEntitiesRequest<librbd::MockTestImageCtx> {
+  std::map<MirrorEntity, std::string> *entities = nullptr;
   Context *on_finish = nullptr;
-  static RefreshImagesRequest *s_instance;
-  static RefreshImagesRequest *create(librados::IoCtx &io_ctx,
-                                      ImageIds *image_ids,
+  static RefreshEntitiesRequest *s_instance;
+  static RefreshEntitiesRequest *create(librados::IoCtx &io_ctx,
+                                      std::map<MirrorEntity, std::string> *entities,
                                       Context *on_finish) {
     ceph_assert(s_instance != nullptr);
-    s_instance->image_ids = image_ids;
+    s_instance->entities = entities;
     s_instance->on_finish = on_finish;
     return s_instance;
   }
 
   MOCK_METHOD0(send, void());
 
-  RefreshImagesRequest() {
+  RefreshEntitiesRequest() {
     s_instance = this;
   }
 };
 
-RefreshImagesRequest<librbd::MockTestImageCtx> *RefreshImagesRequest<librbd::MockTestImageCtx>::s_instance = nullptr;
+RefreshEntitiesRequest<librbd::MockTestImageCtx> *RefreshEntitiesRequest<librbd::MockTestImageCtx>::s_instance = nullptr;
 
 } // namespace pool_watcher
 
@@ -160,7 +160,7 @@ class TestMockPoolWatcher : public TestMockFixture {
 public:
   typedef PoolWatcher<librbd::MockTestImageCtx> MockPoolWatcher;
   typedef Threads<librbd::MockTestImageCtx> MockThreads;
-  typedef pool_watcher::RefreshImagesRequest<librbd::MockTestImageCtx> MockRefreshImagesRequest;
+  typedef pool_watcher::RefreshEntitiesRequest<librbd::MockTestImageCtx> MockRefreshEntitiesRequest;
   typedef librbd::MockMirroringWatcher MockMirroringWatcher;
   typedef librbd::MirroringWatcher<librbd::MockTestImageCtx> MirroringWatcher;
 
@@ -170,12 +170,13 @@ public:
     MockListener(TestMockPoolWatcher *test) : test(test) {
     }
 
-    MOCK_METHOD3(mock_handle_update, void(const std::string &, const ImageIds &,
-                                          const ImageIds &));
+    MOCK_METHOD3(mock_handle_update, void(const std::string &,
+                                          const MirrorEntities &,
+                                          const MirrorEntities &));
     void handle_update(const std::string &mirror_uuid,
-                       ImageIds &&added_image_ids,
-                       ImageIds &&removed_image_ids) override {
-      mock_handle_update(mirror_uuid, added_image_ids, removed_image_ids);
+                       MirrorEntities &&added_entities,
+                       MirrorEntities &&removed_entities) override {
+      mock_handle_update(mirror_uuid, added_entities, removed_entities);
     }
   };
 
@@ -206,21 +207,22 @@ public:
       .WillOnce(CompleteContext(r));
   }
 
-  void expect_refresh_images(MockRefreshImagesRequest &request,
-                             const ImageIds &image_ids, int r) {
+  void expect_refresh_entities(MockRefreshEntitiesRequest &request,
+                             const std::map<MirrorEntity, std::string> &entities,
+                             int r) {
     EXPECT_CALL(request, send())
-      .WillOnce(Invoke([&request, image_ids, r]() {
-          *request.image_ids = image_ids;
+      .WillOnce(Invoke([&request, entities, r]() {
+          *request.entities = entities;
           request.on_finish->complete(r);
         }));
   }
 
   void expect_listener_handle_update(MockListener &mock_listener,
                                      const std::string &mirror_uuid,
-                                     const ImageIds &added_image_ids,
-                                     const ImageIds &removed_image_ids) {
-    EXPECT_CALL(mock_listener, mock_handle_update(mirror_uuid, added_image_ids,
-                                                  removed_image_ids))
+                                     const MirrorEntities &added_entities,
+                                     const MirrorEntities &removed_entities) {
+    EXPECT_CALL(mock_listener, mock_handle_update(mirror_uuid, added_entities,
+                                                  removed_entities))
       .WillOnce(WithoutArgs(Invoke([this]() {
           std::lock_guard locker{m_lock};
           ++m_update_count;
@@ -258,6 +260,15 @@ public:
     }
   }
 
+  template <typename K, typename V>
+  std::set<K> get_keys(const std::map<K, V> &key_vals) {
+    std::set<K> keys;
+    for (auto &[key, val] : key_vals) {
+      keys.insert(key);
+    }
+    return keys;
+  }
+
   ceph::mutex m_lock = ceph::make_mutex("TestMockPoolWatcher::m_lock");
   ceph::condition_variable m_cond;
   uint32_t m_update_count = 0;
@@ -272,8 +283,8 @@ TEST_F(TestMockPoolWatcher, EmptyPool) {
   expect_mirroring_watcher_is_unregistered(mock_mirroring_watcher, true);
   expect_mirroring_watcher_register(mock_mirroring_watcher, 0);
 
-  MockRefreshImagesRequest mock_refresh_images_request;
-  expect_refresh_images(mock_refresh_images_request, {}, 0);
+  MockRefreshEntitiesRequest mock_refresh_entities_request;
+  expect_refresh_entities(mock_refresh_entities_request, {}, 0);
 
   MockListener mock_listener(this);
   expect_listener_handle_update(mock_listener, "remote uuid", {}, {});
@@ -298,14 +309,15 @@ TEST_F(TestMockPoolWatcher, NonEmptyPool) {
   expect_mirroring_watcher_is_unregistered(mock_mirroring_watcher, true);
   expect_mirroring_watcher_register(mock_mirroring_watcher, 0);
 
-  ImageIds image_ids{
-    {"global id 1", "remote id 1"},
-    {"global id 2", "remote id 2"}};
-  MockRefreshImagesRequest mock_refresh_images_request;
-  expect_refresh_images(mock_refresh_images_request, image_ids, 0);
+  std::map<MirrorEntity, std::string> entities{
+    {{MIRROR_ENTITY_TYPE_IMAGE, "global id 1", 1}, "remote id 1"},
+    {{MIRROR_ENTITY_TYPE_IMAGE, "global id 2", 1}, "remote id 2"}};
+  MockRefreshEntitiesRequest mock_refresh_entities_request;
+  expect_refresh_entities(mock_refresh_entities_request, entities, 0);
 
   MockListener mock_listener(this);
-  expect_listener_handle_update(mock_listener, "remote uuid", image_ids, {});
+  expect_listener_handle_update(mock_listener, "remote uuid",
+                                get_keys(entities), {});
 
   MockPoolWatcher mock_pool_watcher(&mock_threads, m_remote_io_ctx,
                                     "remote uuid", mock_listener);
@@ -327,15 +339,15 @@ TEST_F(TestMockPoolWatcher, NotifyDuringRefresh) {
   expect_mirroring_watcher_is_unregistered(mock_mirroring_watcher, true);
   expect_mirroring_watcher_register(mock_mirroring_watcher, 0);
 
-  ImageIds image_ids{
-    {"global id 1", "remote id 1"},
-    {"global id 2", "remote id 2"}};
-  MockRefreshImagesRequest mock_refresh_images_request;
+  std::map<MirrorEntity, std::string> entities{
+    {{MIRROR_ENTITY_TYPE_IMAGE, "global id 1", 1}, "remote id 1"},
+    {{MIRROR_ENTITY_TYPE_IMAGE, "global id 2", 1}, "remote id 2"}};
+  MockRefreshEntitiesRequest mock_refresh_entities_request;
   bool refresh_sent = false;
-  EXPECT_CALL(mock_refresh_images_request, send())
-    .WillOnce(Invoke([this, &mock_refresh_images_request, &image_ids,
+  EXPECT_CALL(mock_refresh_entities_request, send())
+    .WillOnce(Invoke([this, &mock_refresh_entities_request, &entities,
                       &refresh_sent]() {
-       *mock_refresh_images_request.image_ids = image_ids;
+       *mock_refresh_entities_request.entities = entities;
 
         std::lock_guard locker{m_lock};
         refresh_sent = true;
@@ -344,10 +356,11 @@ TEST_F(TestMockPoolWatcher, NotifyDuringRefresh) {
 
 
   MockListener mock_listener(this);
-  image_ids = {
-    {"global id 1", "remote id 1a"},
-    {"global id 3", "remote id 3"}};
-  expect_listener_handle_update(mock_listener, "remote uuid", image_ids, {});
+  entities = {
+    {{MIRROR_ENTITY_TYPE_IMAGE, "global id 1", 1}, "remote id 1a"},
+    {{MIRROR_ENTITY_TYPE_IMAGE, "global id 3", 1}, "remote id 3"}};
+  expect_listener_handle_update(mock_listener, "remote uuid",
+                                get_keys(entities), {});
 
   MockPoolWatcher mock_pool_watcher(&mock_threads, m_remote_io_ctx,
                                     "remote uuid", mock_listener);
@@ -365,7 +378,7 @@ TEST_F(TestMockPoolWatcher, NotifyDuringRefresh) {
   MirroringWatcher::get_instance().handle_image_updated(
     cls::rbd::MIRROR_IMAGE_STATE_ENABLED, "remote id 3", "global id 3");
 
-  mock_refresh_images_request.on_finish->complete(0);
+  mock_refresh_entities_request.on_finish->complete(0);
   ASSERT_TRUE(wait_for_update(1));
 
   expect_mirroring_watcher_unregister(mock_mirroring_watcher, 0);
@@ -380,11 +393,11 @@ TEST_F(TestMockPoolWatcher, Notify) {
   expect_mirroring_watcher_is_unregistered(mock_mirroring_watcher, true);
   expect_mirroring_watcher_register(mock_mirroring_watcher, 0);
 
-  ImageIds image_ids{
-    {"global id 1", "remote id 1"},
-    {"global id 2", "remote id 2"}};
-  MockRefreshImagesRequest mock_refresh_images_request;
-  expect_refresh_images(mock_refresh_images_request, image_ids, 0);
+  std::map<MirrorEntity, std::string> entities{
+    {{MIRROR_ENTITY_TYPE_IMAGE, "global id 1", 1}, "remote id 1"},
+    {{MIRROR_ENTITY_TYPE_IMAGE, "global id 2", 1}, "remote id 2"}};
+  MockRefreshEntitiesRequest mock_refresh_entities_request;
+  expect_refresh_entities(mock_refresh_entities_request, entities, 0);
 
   EXPECT_CALL(*mock_threads.work_queue, queue(_, _))
     .WillOnce(Invoke([this](Context *ctx, int r) {
@@ -392,7 +405,8 @@ TEST_F(TestMockPoolWatcher, Notify) {
       }));
 
   MockListener mock_listener(this);
-  expect_listener_handle_update(mock_listener, "remote uuid", image_ids, {});
+  expect_listener_handle_update(mock_listener, "remote uuid",
+                                get_keys(entities), {});
 
   Context *notify_ctx = nullptr;
   EXPECT_CALL(*mock_threads.work_queue, queue(_, _))
@@ -404,8 +418,10 @@ TEST_F(TestMockPoolWatcher, Notify) {
       }));
   expect_listener_handle_update(
     mock_listener, "remote uuid",
-    {{"global id 1", "remote id 1a"}, {"global id 3", "remote id 3"}},
-    {{"global id 1", "remote id 1"}, {"global id 2", "remote id 2"}});
+    {{MIRROR_ENTITY_TYPE_IMAGE, "global id 1", 1},
+     {MIRROR_ENTITY_TYPE_IMAGE, "global id 3", 1}},
+    {{MIRROR_ENTITY_TYPE_IMAGE, "global id 1", 1},
+     {MIRROR_ENTITY_TYPE_IMAGE, "global id 2", 1}});
 
   MockPoolWatcher mock_pool_watcher(&mock_threads, m_remote_io_ctx,
                                     "remote uuid", mock_listener);
@@ -468,8 +484,8 @@ TEST_F(TestMockPoolWatcher, RegisterWatcherMissing) {
   expect_mirroring_watcher_is_unregistered(mock_mirroring_watcher, true);
   expect_mirroring_watcher_register(mock_mirroring_watcher, 0);
 
-  MockRefreshImagesRequest mock_refresh_images_request;
-  expect_refresh_images(mock_refresh_images_request, {}, 0);
+  MockRefreshEntitiesRequest mock_refresh_entities_request;
+  expect_refresh_entities(mock_refresh_entities_request, {}, 0);
 
   MockListener mock_listener(this);
   expect_listener_handle_update(mock_listener, "remote uuid", {}, {});
@@ -498,8 +514,8 @@ TEST_F(TestMockPoolWatcher, RegisterWatcherError) {
   expect_mirroring_watcher_is_unregistered(mock_mirroring_watcher, true);
   expect_mirroring_watcher_register(mock_mirroring_watcher, 0);
 
-  MockRefreshImagesRequest mock_refresh_images_request;
-  expect_refresh_images(mock_refresh_images_request, {}, 0);
+  MockRefreshEntitiesRequest mock_refresh_entities_request;
+  expect_refresh_entities(mock_refresh_entities_request, {}, 0);
 
   MockListener mock_listener(this);
   expect_listener_handle_update(mock_listener, "remote uuid", {}, {});
@@ -524,8 +540,8 @@ TEST_F(TestMockPoolWatcher, RefreshBlocklist) {
   expect_mirroring_watcher_is_unregistered(mock_mirroring_watcher, true);
   expect_mirroring_watcher_register(mock_mirroring_watcher, 0);
 
-  MockRefreshImagesRequest mock_refresh_images_request;
-  expect_refresh_images(mock_refresh_images_request, {}, -EBLOCKLISTED);
+  MockRefreshEntitiesRequest mock_refresh_entities_request;
+  expect_refresh_entities(mock_refresh_entities_request, {}, -EBLOCKLISTED);
 
   MockListener mock_listener(this);
   MockPoolWatcher mock_pool_watcher(&mock_threads, m_remote_io_ctx,
@@ -548,8 +564,8 @@ TEST_F(TestMockPoolWatcher, RefreshMissing) {
   expect_mirroring_watcher_is_unregistered(mock_mirroring_watcher, true);
   expect_mirroring_watcher_register(mock_mirroring_watcher, 0);
 
-  MockRefreshImagesRequest mock_refresh_images_request;
-  expect_refresh_images(mock_refresh_images_request, {}, -ENOENT);
+  MockRefreshEntitiesRequest mock_refresh_entities_request;
+  expect_refresh_entities(mock_refresh_entities_request, {}, -ENOENT);
 
   MockListener mock_listener(this);
   expect_listener_handle_update(mock_listener, "remote uuid", {}, {});
@@ -574,12 +590,12 @@ TEST_F(TestMockPoolWatcher, RefreshError) {
   expect_mirroring_watcher_is_unregistered(mock_mirroring_watcher, true);
   expect_mirroring_watcher_register(mock_mirroring_watcher, 0);
 
-  MockRefreshImagesRequest mock_refresh_images_request;
-  expect_refresh_images(mock_refresh_images_request, {}, -EINVAL);
+  MockRefreshEntitiesRequest mock_refresh_entities_request;
+  expect_refresh_entities(mock_refresh_entities_request, {}, -EINVAL);
   expect_timer_add_event(mock_threads);
 
   expect_mirroring_watcher_is_unregistered(mock_mirroring_watcher, false);
-  expect_refresh_images(mock_refresh_images_request, {}, 0);
+  expect_refresh_entities(mock_refresh_entities_request, {}, 0);
 
   MockListener mock_listener(this);
   expect_listener_handle_update(mock_listener, "remote uuid", {}, {});
@@ -604,17 +620,17 @@ TEST_F(TestMockPoolWatcher, Rewatch) {
   expect_mirroring_watcher_is_unregistered(mock_mirroring_watcher, true);
   expect_mirroring_watcher_register(mock_mirroring_watcher, 0);
 
-  MockRefreshImagesRequest mock_refresh_images_request;
-  expect_refresh_images(mock_refresh_images_request, {}, 0);
+  MockRefreshEntitiesRequest mock_refresh_entities_request;
+  expect_refresh_entities(mock_refresh_entities_request, {}, 0);
 
   MockListener mock_listener(this);
   expect_listener_handle_update(mock_listener, "remote uuid", {}, {});
 
   expect_timer_add_event(mock_threads);
   expect_mirroring_watcher_is_unregistered(mock_mirroring_watcher, false);
-  expect_refresh_images(mock_refresh_images_request, {{"global id", "image id"}}, 0);
-  expect_listener_handle_update(mock_listener, "remote uuid",
-                                {{"global id", "image id"}}, {});
+  MirrorEntity entity = {MIRROR_ENTITY_TYPE_IMAGE, "global id", 1};
+  expect_refresh_entities(mock_refresh_entities_request, {{entity, "image id"}}, 0);
+  expect_listener_handle_update(mock_listener, "remote uuid", {entity}, {});
 
   MockPoolWatcher mock_pool_watcher(&mock_threads, m_remote_io_ctx,
                                     "remote uuid", mock_listener);
@@ -639,8 +655,8 @@ TEST_F(TestMockPoolWatcher, RewatchBlocklist) {
   expect_mirroring_watcher_is_unregistered(mock_mirroring_watcher, true);
   expect_mirroring_watcher_register(mock_mirroring_watcher, 0);
 
-  MockRefreshImagesRequest mock_refresh_images_request;
-  expect_refresh_images(mock_refresh_images_request, {}, 0);
+  MockRefreshEntitiesRequest mock_refresh_entities_request;
+  expect_refresh_entities(mock_refresh_entities_request, {}, 0);
 
   MockListener mock_listener(this);
   expect_listener_handle_update(mock_listener, "remote uuid", {}, {});
@@ -668,17 +684,17 @@ TEST_F(TestMockPoolWatcher, RewatchError) {
   expect_mirroring_watcher_is_unregistered(mock_mirroring_watcher, true);
   expect_mirroring_watcher_register(mock_mirroring_watcher, 0);
 
-  MockRefreshImagesRequest mock_refresh_images_request;
-  expect_refresh_images(mock_refresh_images_request, {}, 0);
+  MockRefreshEntitiesRequest mock_refresh_entities_request;
+  expect_refresh_entities(mock_refresh_entities_request, {}, 0);
 
   MockListener mock_listener(this);
   expect_listener_handle_update(mock_listener, "remote uuid", {}, {});
 
   expect_timer_add_event(mock_threads);
   expect_mirroring_watcher_is_unregistered(mock_mirroring_watcher, false);
-  expect_refresh_images(mock_refresh_images_request, {{"global id", "image id"}}, 0);
-  expect_listener_handle_update(mock_listener, "remote uuid",
-                                {{"global id", "image id"}}, {});
+  MirrorEntity entity = {MIRROR_ENTITY_TYPE_IMAGE, "global id", 1};
+  expect_refresh_entities(mock_refresh_entities_request, {{entity, "image id"}}, 0);
+  expect_listener_handle_update(mock_listener, "remote uuid", {entity}, {});
 
   MockPoolWatcher mock_pool_watcher(&mock_threads, m_remote_io_ctx,
                                     "remote uuid", mock_listener);
@@ -703,18 +719,18 @@ TEST_F(TestMockPoolWatcher, DeferredRefresh) {
   expect_mirroring_watcher_is_unregistered(mock_mirroring_watcher, true);
   expect_mirroring_watcher_register(mock_mirroring_watcher, 0);
 
-  MockRefreshImagesRequest mock_refresh_images_request;
+  MockRefreshEntitiesRequest mock_refresh_entities_request;
 
-  EXPECT_CALL(mock_refresh_images_request, send())
-    .WillOnce(Invoke([&mock_refresh_images_request]() {
-        *mock_refresh_images_request.image_ids = {};
+  EXPECT_CALL(mock_refresh_entities_request, send())
+    .WillOnce(Invoke([&mock_refresh_entities_request]() {
+        *mock_refresh_entities_request.entities = {};
         MirroringWatcher::get_instance().handle_rewatch_complete(0);
-        mock_refresh_images_request.on_finish->complete(0);
+        mock_refresh_entities_request.on_finish->complete(0);
         }));
   expect_timer_add_event(mock_threads);
 
   expect_mirroring_watcher_is_unregistered(mock_mirroring_watcher, false);
-  expect_refresh_images(mock_refresh_images_request, {}, 0);
+  expect_refresh_entities(mock_refresh_entities_request, {}, 0);
 
   MockListener mock_listener(this);
   expect_listener_handle_update(mock_listener, "remote uuid", {}, {});
index 42a8fcc18861163c040610139562d1588b3b4755..193a038d18fce0cb10b6a01410bdea0bc798bc67 100644 (file)
@@ -61,7 +61,7 @@ set(rbd_mirror_internal
   image_sync/SyncPointCreateRequest.cc
   image_sync/SyncPointPruneRequest.cc
   image_sync/Utils.cc
-  pool_watcher/RefreshImagesRequest.cc
+  pool_watcher/RefreshEntitiesRequest.cc
   service_daemon/Types.cc)
 
 add_library(rbd_mirror_internal STATIC
index 25fb8767459ce5a0092d669057dc65c5c6bd10c3..f8d4381e37b4735c0c864c887cd5cc0743f2efc3 100644 (file)
@@ -27,6 +27,8 @@ namespace mirror {
 
 using ::operator<<;
 using image_map::Policy;
+using image_map::GlobalId;
+using image_map::GlobalIds;
 
 using librbd::util::unique_lock_name;
 using librbd::util::create_async_context_callback;
@@ -34,21 +36,21 @@ using librbd::util::create_async_context_callback;
 template <typename I>
 struct ImageMap<I>::C_NotifyInstance : public Context {
   ImageMap* image_map;
-  std::string global_image_id;
+  GlobalId global_id;
   bool acquire_release;
 
-  C_NotifyInstance(ImageMap* image_map, const std::string& global_image_id,
+  C_NotifyInstance(ImageMap* image_map, const GlobalId& global_id,
                    bool acquire_release)
-    : image_map(image_map), global_image_id(global_image_id),
+    : image_map(image_map), global_id(global_id),
       acquire_release(acquire_release) {
     image_map->start_async_op();
   }
 
   void finish(int r) override {
     if (acquire_release) {
-      image_map->handle_peer_ack(global_image_id, r);
+      image_map->handle_peer_ack(global_id, r);
     } else {
-      image_map->handle_peer_ack_remove(global_image_id, r);
+      image_map->handle_peer_ack_remove(global_id, r);
     }
     image_map->finish_async_op();
   }
@@ -72,8 +74,7 @@ ImageMap<I>::~ImageMap() {
 }
 
 template <typename I>
-void ImageMap<I>::continue_action(const std::set<std::string> &global_image_ids,
-                                  int r) {
+void ImageMap<I>::continue_action(const GlobalIds &global_ids, int r) {
   dout(20) << dendl;
 
   {
@@ -82,10 +83,10 @@ void ImageMap<I>::continue_action(const std::set<std::string> &global_image_ids,
       return;
     }
 
-    for (auto const &global_image_id : global_image_ids) {
-      bool schedule = m_policy->finish_action(global_image_id, r);
+    for (auto const &global_id : global_ids) {
+      bool schedule = m_policy->finish_action(global_id, r);
       if (schedule) {
-        schedule_action(global_image_id);
+        schedule_action(global_id);
       }
     }
   }
@@ -95,24 +96,22 @@ void ImageMap<I>::continue_action(const std::set<std::string> &global_image_ids,
 
 template <typename I>
 void ImageMap<I>::handle_update_request(
-    const Updates &updates,
-    const std::set<std::string> &remove_global_image_ids, int r) {
+    const Updates &updates, const GlobalIds &remove_global_ids, int r) {
   dout(20) << "r=" << r << dendl;
 
-  std::set<std::string> global_image_ids;
+  GlobalIds global_ids;
 
-  global_image_ids.insert(remove_global_image_ids.begin(),
-                          remove_global_image_ids.end());
+  global_ids.insert(remove_global_ids.begin(), remove_global_ids.end());
   for (auto const &update : updates) {
-    global_image_ids.insert(update.global_image_id);
+    global_ids.insert({update.entity.type, update.entity.global_id});
   }
 
-  continue_action(global_image_ids, r);
+  continue_action(global_ids, r);
 }
 
 template <typename I>
-void ImageMap<I>::update_image_mapping(Updates&& map_updates,
-                                       std::set<std::string>&& map_removals) {
+void ImageMap<I>::update_image_mapping(Updates &&map_updates,
+                                       GlobalIds &&map_removals) {
   if (map_updates.empty() && map_removals.empty()) {
     return;
   }
@@ -130,15 +129,15 @@ void ImageMap<I>::update_image_mapping(Updates&& map_updates,
   // empty meta policy for now..
   image_map::PolicyMetaNone policy_meta;
 
-  bufferlist bl;
-  encode(image_map::PolicyData(policy_meta), bl);
-
   // prepare update map
-  std::map<std::string, cls::rbd::MirrorImageMap> update_mapping;
+  std::map<GlobalId, cls::rbd::MirrorImageMap> update_mapping;
   for (auto const &update : map_updates) {
+    bufferlist bl;
+    encode(image_map::PolicyData(update.entity.count, policy_meta), bl);
+
     update_mapping.emplace(
-      update.global_image_id, cls::rbd::MirrorImageMap(update.instance_id,
-      update.mapped_time, bl));
+        GlobalId{update.entity.type, update.entity.global_id},
+        cls::rbd::MirrorImageMap(update.instance_id, update.mapped_time, bl));
   }
 
   start_async_op();
@@ -155,18 +154,17 @@ void ImageMap<I>::process_updates() {
   ceph_assert(m_timer_task == nullptr);
 
   Updates map_updates;
-  std::set<std::string> map_removals;
+  GlobalIds map_removals;
   Updates acquire_updates;
   Updates release_updates;
 
   // gather updates by advancing the state machine
   m_lock.lock();
-  for (auto const &global_image_id : m_global_image_ids) {
-    image_map::ActionType action_type =
-      m_policy->start_action(global_image_id);
-    image_map::LookupInfo info = m_policy->lookup(global_image_id);
+  for (auto const &global_id : m_global_ids) {
+    image_map::ActionType action_type = m_policy->start_action(global_id);
+    image_map::LookupInfo info = m_policy->lookup(global_id);
 
-    dout(15) << "global_image_id=" << global_image_id << ", "
+    dout(15) << "global_id=" << global_id << ", "
              << "action=" << action_type << ", "
              << "instance=" << info.instance_id << dendl;
     switch (action_type) {
@@ -174,23 +172,28 @@ void ImageMap<I>::process_updates() {
       continue;
     case image_map::ACTION_TYPE_MAP_UPDATE:
       ceph_assert(info.instance_id != image_map::UNMAPPED_INSTANCE_ID);
-      map_updates.emplace_back(global_image_id, info.instance_id,
-                               info.mapped_time);
+      map_updates.emplace_back(
+          MirrorEntity{global_id.type, global_id.id, info.weight},
+          info.instance_id, info.mapped_time);
       break;
     case image_map::ACTION_TYPE_MAP_REMOVE:
-      map_removals.emplace(global_image_id);
+      map_removals.emplace(global_id);
       break;
     case image_map::ACTION_TYPE_ACQUIRE:
       ceph_assert(info.instance_id != image_map::UNMAPPED_INSTANCE_ID);
-      acquire_updates.emplace_back(global_image_id, info.instance_id);
+      acquire_updates.emplace_back(
+          MirrorEntity{global_id.type, global_id.id, info.weight},
+          info.instance_id);
       break;
     case image_map::ACTION_TYPE_RELEASE:
       ceph_assert(info.instance_id != image_map::UNMAPPED_INSTANCE_ID);
-      release_updates.emplace_back(global_image_id, info.instance_id);
+      release_updates.emplace_back(
+          MirrorEntity{global_id.type, global_id.id, info.weight},
+          info.instance_id);
       break;
     }
   }
-  m_global_image_ids.clear();
+  m_global_ids.clear();
   m_lock.unlock();
 
   // notify listener (acquire, release) and update on-disk map. note
@@ -203,11 +206,14 @@ void ImageMap<I>::process_updates() {
 template <typename I>
 void ImageMap<I>::schedule_update_task() {
   std::lock_guard timer_lock{m_threads->timer_lock};
-  schedule_update_task(m_threads->timer_lock);
+  CephContext *cct = reinterpret_cast<CephContext *>(m_ioctx.cct());
+  double after = cct->_conf.get_val<double>("rbd_mirror_image_policy_update_throttle_interval");
+  schedule_update_task(m_threads->timer_lock, after);
 }
 
 template <typename I>
-void ImageMap<I>::schedule_update_task(const ceph::mutex &timer_lock) {
+void ImageMap<I>::schedule_update_task(const ceph::mutex &timer_lock,
+                                       double after) {
   ceph_assert(ceph_mutex_is_locked(m_threads->timer_lock));
 
   schedule_rebalance_task();
@@ -218,7 +224,7 @@ void ImageMap<I>::schedule_update_task(const ceph::mutex &timer_lock) {
 
   {
     std::lock_guard locker{m_lock};
-    if (m_global_image_ids.empty()) {
+    if (m_global_ids.empty()) {
       return;
     }
   }
@@ -230,9 +236,6 @@ void ImageMap<I>::schedule_update_task(const ceph::mutex &timer_lock) {
       process_updates();
     });
 
-  CephContext *cct = reinterpret_cast<CephContext *>(m_ioctx.cct());
-  double after = cct->_conf.get_val<double>("rbd_mirror_image_policy_update_throttle_interval");
-
   dout(20) << "scheduling image check update (" << m_timer_task << ")"
            << " after " << after << " second(s)" << dendl;
   m_threads->timer->add_event_after(after, m_timer_task);
@@ -244,19 +247,19 @@ void ImageMap<I>::rebalance() {
 
   {
     std::lock_guard locker{m_lock};
-    if (m_async_op_tracker.empty() && m_global_image_ids.empty()){
+    if (m_async_op_tracker.empty() && m_global_ids.empty()){
       dout(20) << "starting rebalance" << dendl;
 
-      std::set<std::string> remap_global_image_ids;
-      m_policy->add_instances({}, &remap_global_image_ids);
+      GlobalIds remap_global_ids;
+      m_policy->add_instances({}, &remap_global_ids);
 
-      for (auto const &global_image_id : remap_global_image_ids) {
-        schedule_action(global_image_id);
+      for (auto const &global_id : remap_global_ids) {
+        schedule_action(global_id);
       }
     }
   }
 
-  schedule_update_task(m_threads->timer_lock);
+  schedule_update_task();
 }
 
 template <typename I>
@@ -290,11 +293,11 @@ void ImageMap<I>::schedule_rebalance_task() {
 }
 
 template <typename I>
-void ImageMap<I>::schedule_action(const std::string &global_image_id) {
-  dout(20) << "global_image_id=" << global_image_id << dendl;
+void ImageMap<I>::schedule_action(const GlobalId &global_id) {
+  dout(20) << "global_id=" << global_id << dendl;
   ceph_assert(ceph_mutex_is_locked(m_lock));
 
-  m_global_image_ids.emplace(global_image_id);
+  m_global_ids.emplace(global_id);
 }
 
 template <typename I>
@@ -308,19 +311,35 @@ void ImageMap<I>::notify_listener_acquire_release_images(
           << "release=[" << release << "]" << dendl;
 
   for (auto const &update : acquire) {
-    m_listener.acquire_image(
-      update.global_image_id, update.instance_id,
-      create_async_context_callback(
-        m_threads->work_queue,
-        new C_NotifyInstance(this, update.global_image_id, true)));
+    auto global_id = GlobalId(update.entity.type, update.entity.global_id);
+    if (update.entity.type == MIRROR_ENTITY_TYPE_IMAGE) {
+      m_listener.acquire_image(
+        update.entity.global_id, update.instance_id,
+        create_async_context_callback(
+          m_threads->work_queue,
+          new C_NotifyInstance(this, global_id, true)));
+    } else if (update.entity.type == MIRROR_ENTITY_TYPE_GROUP) {
+      // TODO
+    } else {
+      ceph_abort_msgf("invalid mirror entity type: %d",
+                      (int)update.entity.type);
+    }
   }
 
   for (auto const &update : release) {
-    m_listener.release_image(
-      update.global_image_id, update.instance_id,
-      create_async_context_callback(
-        m_threads->work_queue,
-        new C_NotifyInstance(this, update.global_image_id, true)));
+    auto global_id = GlobalId(update.entity.type, update.entity.global_id);
+    if (update.entity.type == MIRROR_ENTITY_TYPE_IMAGE || update.entity.count != 0) {
+      m_listener.release_image(
+        update.entity.global_id, update.instance_id,
+        create_async_context_callback(
+          m_threads->work_queue,
+          new C_NotifyInstance(this, global_id, true)));
+    } else if (update.entity.type == MIRROR_ENTITY_TYPE_GROUP) {
+      // TODO
+    } else {
+      ceph_abort_msgf("invalid mirror entity type: %d",
+                      (int)update.entity.type);
+    }
   }
 }
 
@@ -331,16 +350,24 @@ void ImageMap<I>::notify_listener_remove_images(const std::string &mirror_uuid,
           << "remove=[" << remove << "]" << dendl;
 
   for (auto const &update : remove) {
-    m_listener.remove_image(
-      mirror_uuid, update.global_image_id, update.instance_id,
-      create_async_context_callback(
-        m_threads->work_queue,
-        new C_NotifyInstance(this, update.global_image_id, false)));
+    auto global_id = GlobalId(update.entity.type, update.entity.global_id);
+    if (update.entity.type == MIRROR_ENTITY_TYPE_IMAGE) {
+      m_listener.remove_image(
+        mirror_uuid, update.entity.global_id, update.instance_id,
+        create_async_context_callback(
+          m_threads->work_queue,
+          new C_NotifyInstance(this, global_id, false)));
+    } else if (update.entity.type == MIRROR_ENTITY_TYPE_GROUP) {
+      // TODO
+    } else {
+      ceph_abort_msgf("invalid mirror entity type: %d",
+                      (int)update.entity.type);
+    }
   }
 }
 
 template <typename I>
-void ImageMap<I>::handle_load(const std::map<std::string,
+void ImageMap<I>::handle_load(const std::map<GlobalId,
                               cls::rbd::MirrorImageMap> &image_mapping) {
   dout(20) << dendl;
 
@@ -356,16 +383,15 @@ void ImageMap<I>::handle_load(const std::map<std::string,
 }
 
 template <typename I>
-void ImageMap<I>::handle_peer_ack_remove(const std::string &global_image_id,
-                                         int r) {
+void ImageMap<I>::handle_peer_ack_remove(const GlobalId &global_id, int r) {
   std::lock_guard locker{m_lock};
-  dout(5) << "global_image_id=" << global_image_id << dendl;
+  dout(5) << "global_id=" << global_id << dendl;
 
   if (r < 0) {
-    derr << "failed to remove global_image_id=" << global_image_id << dendl;
+    derr << "failed to remove global_id=" << global_id << dendl;
   }
 
-  auto peer_it = m_peer_map.find(global_image_id);
+  auto peer_it = m_peer_map.find(global_id);
   if (peer_it == m_peer_map.end()) {
     return;
   }
@@ -376,16 +402,17 @@ void ImageMap<I>::handle_peer_ack_remove(const std::string &global_image_id,
 template <typename I>
 void ImageMap<I>::update_images_added(
     const std::string &mirror_uuid,
-    const std::set<std::string> &global_image_ids) {
+    const MirrorEntities &entities) {
   dout(5) << "mirror_uuid=" << mirror_uuid << ", "
-          << "global_image_ids=[" << global_image_ids << "]" << dendl;
+          << "entities=[" << entities << "]" << dendl;
   ceph_assert(ceph_mutex_is_locked(m_lock));
 
-  for (auto const &global_image_id : global_image_ids) {
-    auto result = m_peer_map[global_image_id].insert(mirror_uuid);
-    if (result.second && m_peer_map[global_image_id].size() == 1) {
-      if (m_policy->add_image(global_image_id)) {
-        schedule_action(global_image_id);
+  for (auto &entity : entities) {
+    auto global_id = GlobalId(entity.type, entity.global_id);
+    auto result = m_peer_map[global_id].insert(mirror_uuid);
+    if ((result.second || entity.type == MIRROR_ENTITY_TYPE_GROUP)) {
+      if (m_policy->add_entity(global_id, entity.count)) {
+        schedule_action(global_id);
       }
     }
   }
@@ -394,34 +421,35 @@ void ImageMap<I>::update_images_added(
 template <typename I>
 void ImageMap<I>::update_images_removed(
     const std::string &mirror_uuid,
-    const std::set<std::string> &global_image_ids) {
+    const MirrorEntities &entities) {
   dout(5) << "mirror_uuid=" << mirror_uuid << ", "
-          << "global_image_ids=[" << global_image_ids << "]" << dendl;
+          << "entities=[" << entities << "]" << dendl;
   ceph_assert(ceph_mutex_is_locked(m_lock));
 
   Updates to_remove;
-  for (auto const &global_image_id : global_image_ids) {
-    image_map::LookupInfo info = m_policy->lookup(global_image_id);
-    bool image_mapped = (info.instance_id != image_map::UNMAPPED_INSTANCE_ID);
+  for (auto &entity : entities) {
+    auto global_id = GlobalId(entity.type, entity.global_id);
+    image_map::LookupInfo info = m_policy->lookup(global_id);
+    bool entity_mapped = (info.instance_id != image_map::UNMAPPED_INSTANCE_ID);
 
-    bool image_removed = image_mapped;
+    bool entity_removed = entity_mapped;
     bool peer_removed = false;
-    auto peer_it = m_peer_map.find(global_image_id);
+    auto peer_it = m_peer_map.find(global_id);
     if (peer_it != m_peer_map.end()) {
       auto& peer_set = peer_it->second;
       peer_removed = peer_set.erase(mirror_uuid);
-      image_removed = peer_removed && peer_set.empty();
+      entity_removed = peer_removed && peer_set.empty();
     }
 
-    if (image_mapped && peer_removed && !mirror_uuid.empty()) {
+    if (entity_mapped && peer_removed && !mirror_uuid.empty()) {
       // peer image has been deleted
-      to_remove.emplace_back(global_image_id, info.instance_id);
+      to_remove.emplace_back(entity, info.instance_id);
     }
 
-    if (image_removed) {
+    if (entity_removed) {
       // local and peer images have been deleted
-      if (m_policy->remove_image(global_image_id)) {
-        schedule_action(global_image_id);
+      if (m_policy->remove_entity(global_id)) {
+        schedule_action(global_id);
       }
     }
   }
@@ -450,11 +478,11 @@ void ImageMap<I>::update_instances_added(
 
     dout(20) << "instance_ids=" << filtered_instance_ids << dendl;
 
-    std::set<std::string> remap_global_image_ids;
-    m_policy->add_instances(filtered_instance_ids, &remap_global_image_ids);
+    GlobalIds remap_global_ids;
+    m_policy->add_instances(filtered_instance_ids, &remap_global_ids);
 
-    for (auto const &global_image_id : remap_global_image_ids) {
-      schedule_action(global_image_id);
+    for (auto const &global_id : remap_global_ids) {
+      schedule_action(global_id);
     }
   }
 
@@ -478,11 +506,11 @@ void ImageMap<I>::update_instances_removed(
 
     dout(20) << "instance_ids=" << filtered_instance_ids << dendl;
 
-    std::set<std::string> remap_global_image_ids;
-    m_policy->remove_instances(filtered_instance_ids, &remap_global_image_ids);
+    GlobalIds remap_global_ids;
+    m_policy->remove_instances(filtered_instance_ids, &remap_global_ids);
 
-    for (auto const &global_image_id : remap_global_image_ids) {
-      schedule_action(global_image_id);
+    for (auto const &global_id : remap_global_ids) {
+      schedule_action(global_id);
     }
   }
 
@@ -491,11 +519,11 @@ void ImageMap<I>::update_instances_removed(
 
 template <typename I>
 void ImageMap<I>::update_images(const std::string &mirror_uuid,
-                                std::set<std::string> &&added_global_image_ids,
-                                std::set<std::string> &&removed_global_image_ids) {
+                                MirrorEntities &&added_entities,
+                                MirrorEntities &&removed_entities) {
   dout(5) << "mirror_uuid=" << mirror_uuid << ", " << "added_count="
-          << added_global_image_ids.size() << ", " << "removed_count="
-          << removed_global_image_ids.size() << dendl;
+          << added_entities.size() << ", " << "removed_count="
+          << removed_entities.size() << dendl;
 
   {
     std::lock_guard locker{m_lock};
@@ -503,11 +531,11 @@ void ImageMap<I>::update_images(const std::string &mirror_uuid,
       return;
     }
 
-    if (!removed_global_image_ids.empty()) {
-      update_images_removed(mirror_uuid, removed_global_image_ids);
+    if (!removed_entities.empty()) {
+      update_images_removed(mirror_uuid, removed_entities);
     }
-    if (!added_global_image_ids.empty()) {
-      update_images_added(mirror_uuid, added_global_image_ids);
+    if (!added_entities.empty()) {
+      update_images_added(mirror_uuid, added_entities);
     }
   }
 
@@ -515,11 +543,10 @@ void ImageMap<I>::update_images(const std::string &mirror_uuid,
 }
 
 template <typename I>
-void ImageMap<I>::handle_peer_ack(const std::string &global_image_id, int r) {
-  dout (20) << "global_image_id=" << global_image_id << ", r=" << r
-            << dendl;
+void ImageMap<I>::handle_peer_ack(const GlobalId &global_id, int r) {
+  dout (20) << "global_id=" << global_id << ", r=" << r << dendl;
 
-  continue_action({global_image_id}, r);
+  continue_action({global_id}, r);
 }
 
 template <typename I>
index b17437b77069b0f6adbfbee4d6a0646136d01dff..aac7299ef3b37198a6553ebf14fa9f2dd2de9c20 100644 (file)
@@ -42,8 +42,8 @@ public:
 
   // update (add/remove) images
   void update_images(const std::string &mirror_uuid,
-                     std::set<std::string> &&added_global_image_ids,
-                     std::set<std::string> &&removed_global_image_ids);
+                     MirrorEntities &&added_entities,
+                     MirrorEntities &&removed_entities);
 
   // add/remove instances
   void update_instances_added(const std::vector<std::string> &instances);
@@ -56,23 +56,21 @@ private:
            const std::string& instance_id, image_map::Listener &listener);
 
   struct Update {
-    std::string global_image_id;
+    MirrorEntity entity;
     std::string instance_id;
     utime_t mapped_time;
 
-    Update(const std::string &global_image_id, const std::string &instance_id,
+    Update(const MirrorEntity &entity,  const std::string &instance_id,
            utime_t mapped_time)
-      : global_image_id(global_image_id),
-        instance_id(instance_id),
-        mapped_time(mapped_time) {
+      : entity(entity), instance_id(instance_id), mapped_time(mapped_time) {
     }
-    Update(const std::string &global_image_id, const std::string &instance_id)
-      : Update(global_image_id, instance_id, ceph_clock_now()) {
+    Update(const MirrorEntity &entity, const std::string &instance_id)
+      : Update(entity, instance_id, ceph_clock_now()) {
     }
 
     friend std::ostream& operator<<(std::ostream& os,
                                     const Update& update) {
-      os << "{global_image_id=" << update.global_image_id << ", "
+      os << "{entity=" << update.entity << ", "
          << "instance_id=" << update.instance_id << "}";
       return os;
     }
@@ -94,10 +92,10 @@ private:
   bool m_shutting_down = false;
   AsyncOpTracker m_async_op_tracker;
 
-  // global_image_id -> registered peers ("" == local, remote otherwise)
-  std::map<std::string, std::set<std::string> > m_peer_map;
+  // global_id -> registered peers ("" == local, remote otherwise)
+  std::map<image_map::GlobalId, std::set<std::string>> m_peer_map;
 
-  std::set<std::string> m_global_image_ids;
+  image_map::GlobalIds m_global_ids;
 
   Context *m_rebalance_task = nullptr;
 
@@ -105,7 +103,7 @@ private:
     ImageMap *image_map;
     Context *on_finish;
 
-    std::map<std::string, cls::rbd::MirrorImageMap> image_mapping;
+    std::map<image_map::GlobalId, cls::rbd::MirrorImageMap> image_mapping;
 
     C_LoadMap(ImageMap *image_map, Context *on_finish)
       : image_map(image_map),
@@ -133,37 +131,40 @@ private:
     m_async_op_tracker.wait_for_ops(on_finish);
   }
 
-  void handle_peer_ack(const std::string &global_image_id, int r);
-  void handle_peer_ack_remove(const std::string &global_image_id, int r);
+  void handle_peer_ack(const image_map::GlobalId &global_id, int r);
+  void handle_peer_ack_remove(const image_map::GlobalId &global_id, int r);
 
-  void handle_load(const std::map<std::string, cls::rbd::MirrorImageMap> &image_mapping);
+  void handle_load(const std::map<image_map::GlobalId,
+                                  cls::rbd::MirrorImageMap> &image_mapping);
   void handle_update_request(const Updates &updates,
-                             const std::set<std::string> &remove_global_image_ids, int r);
+                             const image_map::GlobalIds &remove_global_ids,
+                             int r);
 
   // continue (retry or resume depending on state machine) processing
   // current action.
-  void continue_action(const std::set<std::string> &global_image_ids, int r);
+  void continue_action(const image_map::GlobalIds &global_id, int r);
 
   // schedule an image for update
-  void schedule_action(const std::string &global_image_id);
+  void schedule_action(const image_map::GlobalId &global_id);
 
   void schedule_update_task();
-  void schedule_update_task(const ceph::mutex &timer_lock);
+  void schedule_update_task(const ceph::mutex &timer_lock, double after);
   void process_updates();
   void update_image_mapping(Updates&& map_updates,
-                            std::set<std::string>&& map_removals);
+                            image_map::GlobalIds&& map_removals);
 
   void rebalance();
   void schedule_rebalance_task();
 
-  void notify_listener_acquire_release_images(const Updates &acquire, const Updates &release);
+  void notify_listener_acquire_release_images(const Updates &acquire,
+                                              const Updates &release);
   void notify_listener_remove_images(const std::string &mirror_uuid,
                                      const Updates &remove);
 
   void update_images_added(const std::string &mirror_uuid,
-                           const std::set<std::string> &global_image_ids);
+                           const MirrorEntities &entities);
   void update_images_removed(const std::string &mirror_uuid,
-                             const std::set<std::string> &global_image_ids);
+                             const MirrorEntities &entities);
 
   void filter_instance_ids(const std::vector<std::string> &instance_ids,
                            std::vector<std::string> *filtered_instance_ids,
index e0c24535add0ea24524616aaf27367c236c8f408..3cdfa92b0dacbb897445db78c31cb78ed61c7873 100644 (file)
@@ -187,8 +187,8 @@ void NamespaceReplayer<I>::flush()
 
 template <typename I>
 void NamespaceReplayer<I>::handle_update(const std::string &mirror_uuid,
-                                         ImageIds &&added_image_ids,
-                                         ImageIds &&removed_image_ids) {
+                                         MirrorEntities &&added_entities,
+                                         MirrorEntities &&removed_entities) {
   std::lock_guard locker{m_lock};
 
   if (!m_image_map) {
@@ -197,8 +197,8 @@ void NamespaceReplayer<I>::handle_update(const std::string &mirror_uuid,
   }
 
   dout(10) << "mirror_uuid=" << mirror_uuid << ", "
-           << "added_count=" << added_image_ids.size() << ", "
-           << "removed_count=" << removed_image_ids.size() << dendl;
+           << "added_count=" << added_entities.size() << ", "
+           << "removed_count=" << removed_entities.size() << dendl;
 
   m_service_daemon->add_or_update_namespace_attribute(
     m_local_io_ctx.get_id(), m_local_io_ctx.get_namespace(),
@@ -210,19 +210,8 @@ void NamespaceReplayer<I>::handle_update(const std::string &mirror_uuid,
       m_remote_pool_watcher->get_image_count());
   }
 
-  std::set<std::string> added_global_image_ids;
-  for (auto& image_id : added_image_ids) {
-    added_global_image_ids.insert(image_id.global_id);
-  }
-
-  std::set<std::string> removed_global_image_ids;
-  for (auto& image_id : removed_image_ids) {
-    removed_global_image_ids.insert(image_id.global_id);
-  }
-
-  m_image_map->update_images(mirror_uuid,
-                             std::move(added_global_image_ids),
-                             std::move(removed_global_image_ids));
+  m_image_map->update_images(mirror_uuid, std::move(added_entities),
+                             std::move(removed_entities));
 }
 
 template <typename I>
index 25b3369de787dae2b31265da93ddaa87239c3055..262ffb0cd7950b9af233a107fb4d2610ec9e2dd6 100644 (file)
@@ -160,11 +160,11 @@ private:
     }
 
     void handle_update(const std::string &mirror_uuid,
-                       ImageIds &&added_image_ids,
-                       ImageIds &&removed_image_ids) override {
+                       MirrorEntities &&added_entities,
+                       MirrorEntities &&removed_entities) override {
       namespace_replayer->handle_update((local ? "" : mirror_uuid),
-                                  std::move(added_image_ids),
-                                   std::move(removed_image_ids));
+                                        std::move(added_entities),
+                                        std::move(removed_entities));
     }
   };
 
@@ -179,14 +179,14 @@ private:
                        const std::string &instance_id,
                        Context* on_finish) override {
       namespace_replayer->handle_acquire_image(global_image_id, instance_id,
-                                          on_finish);
+                                               on_finish);
     }
 
     void release_image(const std::string &global_image_id,
                        const std::string &instance_id,
                        Context* on_finish) override {
       namespace_replayer->handle_release_image(global_image_id, instance_id,
-                                          on_finish);
+                                               on_finish);
     }
 
     void remove_image(const std::string &mirror_uuid,
@@ -199,8 +199,8 @@ private:
   };
 
   void handle_update(const std::string &mirror_uuid,
-                     ImageIds &&added_image_ids,
-                     ImageIds &&removed_image_ids);
+                     MirrorEntities &&added_entities,
+                     MirrorEntities &&removed_entities);
 
   int init_rados(const std::string &cluster_name,
                  const std::string &client_name,
index 13151240579885a2d4f71917fdba9a1dd7754589..b16792019e49b9922ed48d41eaf6c95aa3144cb4 100644 (file)
@@ -15,7 +15,9 @@
 #include "librbd/api/Mirror.h"
 #include "librbd/asio/ContextWQ.h"
 #include "tools/rbd_mirror/Threads.h"
-#include "tools/rbd_mirror/pool_watcher/RefreshImagesRequest.h"
+#include "tools/rbd_mirror/pool_watcher/RefreshEntitiesRequest.h"
+
+#include <numeric>
 
 #define dout_context g_ceph_context
 #define dout_subsys ceph_subsys_rbd_mirror
@@ -52,7 +54,7 @@ public:
 
   void handle_mode_updated(cls::rbd::MirrorMode mirror_mode) override {
     // invalidate all image state and refresh the pool contents
-    m_pool_watcher->schedule_refresh_images(5);
+    m_pool_watcher->schedule_refresh_entities(5);
   }
 
   void handle_image_updated(cls::rbd::MirrorImageState state,
@@ -102,6 +104,16 @@ bool PoolWatcher<I>::is_blocklisted() const {
   return m_blocklisted;
 }
 
+template <typename I>
+size_t PoolWatcher<I>::get_image_count() const {
+  std::lock_guard locker{m_lock};
+  return std::accumulate(m_entities.begin(), m_entities.end(), 0,
+                         [](size_t count,
+                            const std::pair<MirrorEntity, std::string> &p) {
+                           return count + p.first.count;
+                         });
+}
+
 template <typename I>
 void PoolWatcher<I>::init(Context *on_finish) {
   dout(5) << dendl;
@@ -143,14 +155,14 @@ template <typename I>
 void PoolWatcher<I>::register_watcher() {
   {
     std::lock_guard locker{m_lock};
-    ceph_assert(m_image_ids_invalid);
+    ceph_assert(m_entities_invalid);
     ceph_assert(m_refresh_in_progress);
   }
 
   // if the watch registration is in-flight, let the watcher
   // handle the transition -- only (re-)register if it's not registered
   if (!m_mirroring_watcher->is_unregistered()) {
-    refresh_images();
+    refresh_entities();
     return;
   }
 
@@ -169,7 +181,7 @@ void PoolWatcher<I>::handle_register_watcher(int r) {
 
   {
     std::lock_guard locker{m_lock};
-    ceph_assert(m_image_ids_invalid);
+    ceph_assert(m_entities_invalid);
     ceph_assert(m_refresh_in_progress);
     if (r < 0) {
       m_refresh_in_progress = false;
@@ -178,7 +190,7 @@ void PoolWatcher<I>::handle_register_watcher(int r) {
 
   Context *on_init_finish = nullptr;
   if (r >= 0) {
-    refresh_images();
+    refresh_entities();
   } else if (r == -EBLOCKLISTED) {
     dout(0) << "detected client is blocklisted" << dendl;
 
@@ -192,11 +204,11 @@ void PoolWatcher<I>::handle_register_watcher(int r) {
       std::swap(on_init_finish, m_on_init_finish);
     }
 
-    schedule_refresh_images(30);
+    schedule_refresh_entities(30);
   } else {
     derr << "unexpected error registering mirroring directory watch: "
          << cpp_strerror(r) << dendl;
-    schedule_refresh_images(10);
+    schedule_refresh_entities(10);
   }
 
   m_async_op_tracker.finish_op();
@@ -224,32 +236,31 @@ void PoolWatcher<I>::unregister_watcher() {
 }
 
 template <typename I>
-void PoolWatcher<I>::refresh_images() {
+void PoolWatcher<I>::refresh_entities() {
   dout(5) << dendl;
 
   {
     std::lock_guard locker{m_lock};
-    ceph_assert(m_image_ids_invalid);
+    ceph_assert(m_entities_invalid);
     ceph_assert(m_refresh_in_progress);
 
     // clear all pending notification events since we need to perform
-    // a full image list refresh
-    m_pending_added_image_ids.clear();
-    m_pending_removed_image_ids.clear();
+    // a full entity list refresh
+    m_pending_added_entities.clear();
+    m_pending_removed_entities.clear();
   }
 
   m_async_op_tracker.start_op();
-  m_refresh_image_ids.clear();
+  m_refresh_entities.clear();
   Context *ctx = create_context_callback<
-    PoolWatcher, &PoolWatcher<I>::handle_refresh_images>(this);
-  auto req = pool_watcher::RefreshImagesRequest<I>::create(m_io_ctx,
-                                                           &m_refresh_image_ids,
-                                                           ctx);
+    PoolWatcher, &PoolWatcher<I>::handle_refresh_entities>(this);
+  auto req = pool_watcher::RefreshEntitiesRequest<I>::create(
+    m_io_ctx, &m_refresh_entities, ctx);
   req->send();
 }
 
 template <typename I>
-void PoolWatcher<I>::handle_refresh_images(int r) {
+void PoolWatcher<I>::handle_refresh_entities(int r) {
   dout(5) << "r=" << r << dendl;
 
   bool deferred_refresh = false;
@@ -257,27 +268,27 @@ void PoolWatcher<I>::handle_refresh_images(int r) {
   Context *on_init_finish = nullptr;
   {
     std::lock_guard locker{m_lock};
-    ceph_assert(m_image_ids_invalid);
+    ceph_assert(m_entities_invalid);
     ceph_assert(m_refresh_in_progress);
     m_refresh_in_progress = false;
 
     if (r == -ENOENT) {
       dout(5) << "mirroring directory not found" << dendl;
       r = 0;
-      m_refresh_image_ids.clear();
+      m_refresh_entities.clear();
     }
 
     if (m_deferred_refresh) {
       // need to refresh -- skip the notification
       deferred_refresh = true;
     } else if (r >= 0) {
-      m_pending_image_ids = std::move(m_refresh_image_ids);
-      m_image_ids_invalid = false;
+      m_pending_entities = std::move(m_refresh_entities);
+      m_entities_invalid = false;
       std::swap(on_init_finish, m_on_init_finish);
 
       schedule_listener();
     } else if (r == -EBLOCKLISTED) {
-      dout(0) << "detected client is blocklisted during image refresh" << dendl;
+      dout(0) << "detected client is blocklisted during entity refresh" << dendl;
 
       m_blocklisted = true;
       std::swap(on_init_finish, m_on_init_finish);
@@ -288,11 +299,11 @@ void PoolWatcher<I>::handle_refresh_images(int r) {
 
   if (deferred_refresh) {
     dout(5) << "scheduling deferred refresh" << dendl;
-    schedule_refresh_images(0);
+    schedule_refresh_entities(0);
   } else if (retry_refresh) {
     derr << "failed to retrieve mirroring directory: " << cpp_strerror(r)
          << dendl;
-    schedule_refresh_images(10);
+    schedule_refresh_entities(10);
   }
 
   m_async_op_tracker.finish_op();
@@ -302,7 +313,7 @@ void PoolWatcher<I>::handle_refresh_images(int r) {
 }
 
 template <typename I>
-void PoolWatcher<I>::schedule_refresh_images(double interval) {
+void PoolWatcher<I>::schedule_refresh_entities(double interval) {
   std::scoped_lock locker{m_threads->timer_lock, m_lock};
   if (m_shutting_down || m_refresh_in_progress || m_timer_ctx != nullptr) {
     if (m_refresh_in_progress && !m_deferred_refresh) {
@@ -312,11 +323,11 @@ void PoolWatcher<I>::schedule_refresh_images(double interval) {
     return;
   }
 
-  m_image_ids_invalid = true;
+  m_entities_invalid = true;
   m_timer_ctx = m_threads->timer->add_event_after(
     interval,
     new LambdaContext([this](int r) {
-       process_refresh_images();
+       process_refresh_entities();
       }));
 }
 
@@ -337,7 +348,7 @@ void PoolWatcher<I>::handle_rewatch_complete(int r) {
          << cpp_strerror(r) << dendl;
   }
 
-  schedule_refresh_images(5);
+  schedule_refresh_entities(5);
 }
 
 template <typename I>
@@ -349,15 +360,15 @@ void PoolWatcher<I>::handle_image_updated(const std::string &id,
            << "enabled=" << enabled << dendl;
 
   std::lock_guard locker{m_lock};
-  ImageId image_id(global_image_id, id);
-  m_pending_added_image_ids.erase(image_id);
-  m_pending_removed_image_ids.erase(image_id);
+  MirrorEntity entity(MIRROR_ENTITY_TYPE_IMAGE, global_image_id, 1);
+  m_pending_added_entities.erase(entity);
+  m_pending_removed_entities.erase(entity);
 
   if (enabled) {
-    m_pending_added_image_ids.insert(image_id);
+    m_pending_added_entities.insert({entity, id});
     schedule_listener();
   } else {
-    m_pending_removed_image_ids.insert(image_id);
+    m_pending_removed_entities.insert({entity, id});
     schedule_listener();
   }
 }
@@ -375,7 +386,7 @@ void PoolWatcher<I>::handle_group_updated(const std::string &id,
 }
 
 template <typename I>
-void PoolWatcher<I>::process_refresh_images() {
+void PoolWatcher<I>::process_refresh_entities() {
   ceph_assert(ceph_mutex_is_locked(m_threads->timer_lock));
   ceph_assert(m_timer_ctx != nullptr);
   m_timer_ctx = nullptr;
@@ -400,7 +411,7 @@ template <typename I>
 void PoolWatcher<I>::schedule_listener() {
   ceph_assert(ceph_mutex_is_locked(m_lock));
   m_pending_updates = true;
-  if (m_shutting_down || m_image_ids_invalid || m_notify_listener_in_progress) {
+  if (m_shutting_down || m_entities_invalid || m_notify_listener_in_progress) {
     return;
   }
 
@@ -421,54 +432,65 @@ void PoolWatcher<I>::notify_listener() {
   dout(10) << dendl;
 
   std::string mirror_uuid;
-  ImageIds added_image_ids;
-  ImageIds removed_image_ids;
+  MirrorEntities added_entities;
+  MirrorEntities removed_entities;
   {
     std::lock_guard locker{m_lock};
     ceph_assert(m_notify_listener_in_progress);
 
     // if the watch failed while we didn't own the lock, we are going
     // to need to perform a full refresh
-    if (m_image_ids_invalid) {
+    if (m_entities_invalid) {
       m_notify_listener_in_progress = false;
       return;
     }
 
-    // merge add/remove notifications into pending set (a given image
+    // merge add/remove notifications into pending set (a given entity
     // can only be in one set or another)
-    for (auto &image_id : m_pending_removed_image_ids) {
-      dout(20) << "image_id=" << image_id << dendl;
-      m_pending_image_ids.erase(image_id);
+    for (auto &[entity, id] : m_pending_removed_entities) {
+      dout(20) << "removed pending entity={" << entity << "}" << dendl;
+      m_pending_entities.erase(entity);
+      auto it = m_entities.find(entity);
+      if (it != m_entities.end()) {
+        m_entities.erase(entity);
+      }
+      m_entities.insert({entity, id});
     }
+    m_pending_removed_entities.clear();
 
-    for (auto &image_id : m_pending_added_image_ids) {
-      dout(20) << "image_id=" << image_id << dendl;
-      m_pending_image_ids.erase(image_id);
-      m_pending_image_ids.insert(image_id);
+    for (auto &[entity, id] : m_pending_added_entities) {
+      dout(20) << "added pending entity={" << entity << "}" << dendl;
+      m_pending_entities.erase(entity);
+      m_pending_entities.insert({entity, id});
     }
-    m_pending_added_image_ids.clear();
+    m_pending_added_entities.clear();
 
     // compute added/removed images
-    for (auto &image_id : m_image_ids) {
-      auto it = m_pending_image_ids.find(image_id);
-      if (it == m_pending_image_ids.end() || it->id != image_id.id) {
-        removed_image_ids.insert(image_id);
+    for (auto &[entity, id] : m_entities) {
+      auto it = m_pending_entities.find(entity);
+      // If previous entity is not there in current set of entities or if
+      // their id's don't match then consider its removed
+      if (it == m_pending_entities.end() || it->second != id ||
+          it->first.count < entity.count) {
+        removed_entities.insert(entity);
       }
     }
-    for (auto &image_id : m_pending_image_ids) {
-      auto it = m_image_ids.find(image_id);
-      if (it == m_image_ids.end() || it->id != image_id.id) {
-        added_image_ids.insert(image_id);
+    for (auto &[entity, id] : m_pending_entities) {
+      auto it = m_entities.find(entity);
+      // If current entity is not there in previous set of entities or if
+      // their id's don't match then consider its added
+      if (it == m_entities.end() || it->second != id ||
+          it->first.count < entity.count) {
+        added_entities.insert(entity);
       }
     }
 
     m_pending_updates = false;
-    m_image_ids = m_pending_image_ids;
+    m_entities = m_pending_entities;
   }
 
-  m_listener.handle_update(m_mirror_uuid, std::move(added_image_ids),
-                           std::move(removed_image_ids));
-
+  m_listener.handle_update(m_mirror_uuid, std::move(added_entities),
+                           std::move(removed_entities));
   {
     std::lock_guard locker{m_lock};
     m_notify_listener_in_progress = false;
index b8d96eefbdc585b8a4a7558fa615d53bff7a9036..bcba24fabe8668b6a83d850033f7b97065355f67 100644 (file)
@@ -49,15 +49,11 @@ public:
   PoolWatcher& operator=(const PoolWatcher&) = delete;
 
   bool is_blocklisted() const;
+  size_t get_image_count() const;
 
   void init(Context *on_finish = nullptr);
   void shut_down(Context *on_finish);
 
-  inline uint64_t get_image_count() const {
-    std::lock_guard locker{m_lock};
-    return m_image_ids.size();
-  }
-
 private:
   /**
    * @verbatim
@@ -73,7 +69,7 @@ private:
    *    |/--------------------------------\
    *    |                                 |
    *    v                                 |
-   * REFRESH_IMAGES                       |
+   * REFRESH_ENTITIES                     |
    *    |                                 |
    *    |/----------------------------\   |
    *    |                             |   |
@@ -83,10 +79,7 @@ private:
    *    v                             |   |
    *  IDLE ---\                       |   |
    *    |     |                       |   |
-   *    |     |\---> IMAGE_UPDATED    |   |
-   *    |     |         |             |   |
-   *    |     |         v             |   |
-   *    |     |      GET_IMAGE_NAME --/   |
+   *    |     |\---> ENTITY_UPDATED --/   |
    *    |     |                           |
    *    |     \----> WATCH_ERROR ---------/
    *    v
@@ -107,20 +100,20 @@ private:
   std::string m_mirror_uuid;
   pool_watcher::Listener &m_listener;
 
-  ImageIds m_refresh_image_ids;
+  std::map<MirrorEntity, std::string> m_refresh_entities;
   bufferlist m_out_bl;
 
   mutable ceph::mutex m_lock;
 
   Context *m_on_init_finish = nullptr;
 
-  ImageIds m_image_ids;
+  std::map<MirrorEntity, std::string> m_entities;
 
   bool m_pending_updates = false;
   bool m_notify_listener_in_progress = false;
-  ImageIds m_pending_image_ids;
-  ImageIds m_pending_added_image_ids;
-  ImageIds m_pending_removed_image_ids;
+  std::map<MirrorEntity, std::string> m_pending_entities;
+  std::map<MirrorEntity, std::string> m_pending_added_entities;
+  std::map<MirrorEntity, std::string> m_pending_removed_entities;
 
   MirroringWatcher *m_mirroring_watcher;
 
@@ -129,7 +122,7 @@ private:
   AsyncOpTracker m_async_op_tracker;
   bool m_blocklisted = false;
   bool m_shutting_down = false;
-  bool m_image_ids_invalid = true;
+  bool m_entities_invalid = true;
   bool m_refresh_in_progress = false;
   bool m_deferred_refresh = false;
 
@@ -137,11 +130,11 @@ private:
   void handle_register_watcher(int r);
   void unregister_watcher();
 
-  void refresh_images();
-  void handle_refresh_images(int r);
+  void refresh_entities();
+  void handle_refresh_entities(int r);
 
-  void schedule_refresh_images(double interval);
-  void process_refresh_images();
+  void schedule_refresh_entities(double interval);
+  void process_refresh_entities();
 
   void handle_rewatch_complete(int r);
   void handle_image_updated(const std::string &image_id,
index 21186bae278aad84ea901beb4f9df662f2648c83..7853367c8bf32241ab5284ea1500f6539be5e246 100644 (file)
@@ -1,14 +1,30 @@
 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
 // vim: ts=8 sw=2 smarttab
 
+#include "include/stringify.h"
 #include "tools/rbd_mirror/Types.h"
 
 namespace rbd {
 namespace mirror {
 
-std::ostream &operator<<(std::ostream &os, const ImageId &image_id) {
-  return os << "global id=" << image_id.global_id << ", "
-            << "id=" << image_id.id;
+std::ostream &operator<<(std::ostream &os, const MirrorEntityType &type) {
+  switch (type) {
+  case MIRROR_ENTITY_TYPE_IMAGE:
+    os << "Image";
+    break;
+  case MIRROR_ENTITY_TYPE_GROUP:
+    os << "Group";
+    break;
+  default:
+    os << "Unknown (" << static_cast<uint32_t>(type) << ")";
+    break;
+  }
+  return os;
+}
+
+std::ostream &operator<<(std::ostream &os, const MirrorEntity &entity) {
+  return os << "type=" << entity.type << ", global_id=" << entity.global_id
+            << ", count=" << entity.count;
 }
 
 std::ostream& operator<<(std::ostream& os,
index dee7ab3ebc4116f2270fe0e8952c0bce6f8d33d6..d2b4f57517a505d4ee0ae445d8c25a5177d424d8 100644 (file)
@@ -41,27 +41,36 @@ typedef std::shared_ptr<librados::Rados> RadosRef;
 typedef std::shared_ptr<librados::IoCtx> IoCtxRef;
 typedef std::shared_ptr<librbd::Image> ImageRef;
 
-struct ImageId {
+enum MirrorEntityType {
+  MIRROR_ENTITY_TYPE_IMAGE = 0,
+  MIRROR_ENTITY_TYPE_GROUP = 1,
+};
+
+std::ostream &operator<<(std::ostream &os, const MirrorEntityType &type);
+
+struct MirrorEntity {
+  MirrorEntityType type = MIRROR_ENTITY_TYPE_IMAGE;
   std::string global_id;
-  std::string id;
+  size_t count = 1;
 
-  explicit ImageId(const std::string &global_id) : global_id(global_id) {
-  }
-  ImageId(const std::string &global_id, const std::string &id)
-    : global_id(global_id), id(id) {
+  MirrorEntity(MirrorEntityType type, const std::string &global_id, size_t count)
+    : type(type), global_id(global_id), count(count) {
   }
 
-  inline bool operator==(const ImageId &rhs) const {
-    return (global_id == rhs.global_id && id == rhs.id);
+  inline bool operator==(const MirrorEntity &rhs) const {
+    return type == rhs.type && global_id == rhs.global_id && count == rhs.count;
   }
-  inline bool operator<(const ImageId &rhs) const {
+  inline bool operator<(const MirrorEntity &rhs) const {
+    if (type != rhs.type) {
+      return type < rhs.type;
+    }
     return global_id < rhs.global_id;
   }
 };
 
-std::ostream &operator<<(std::ostream &, const ImageId &image_id);
+std::ostream &operator<<(std::ostream &, const MirrorEntity &entity);
 
-typedef std::set<ImageId> ImageIds;
+typedef std::set<MirrorEntity> MirrorEntities;
 
 struct LocalPoolMeta {
   LocalPoolMeta() {}
index 404248c93223589f8c12b96e39450d0a779f3ae3..bbb1eb337c860ad364d5f942f20c906b6da52ea5 100644 (file)
@@ -28,7 +28,7 @@ using librbd::util::create_context_callback;
 
 template<typename I>
 LoadRequest<I>::LoadRequest(librados::IoCtx &ioctx,
-                            std::map<std::string, cls::rbd::MirrorImageMap> *image_mapping,
+                            std::map<GlobalId, cls::rbd::MirrorImageMap> *image_mapping,
                             Context *on_finish)
   : m_ioctx(ioctx),
     m_image_mapping(image_mapping),
@@ -74,7 +74,16 @@ void LoadRequest<I>::handle_image_map_list(int r) {
     return;
   }
 
-  m_image_mapping->insert(image_mapping.begin(), image_mapping.end());
+  for (auto &[global_id_str, image_map] : image_mapping) {
+    auto global_id = GlobalId(global_id_str);
+    if (global_id.type != MIRROR_ENTITY_TYPE_IMAGE &&
+        global_id.type != MIRROR_ENTITY_TYPE_GROUP) {
+      derr << ": unknown mirror entitiy type " << global_id.type << " for "
+           << global_id_str << dendl;
+      continue;
+    }
+    m_image_mapping->insert({global_id, image_map});
+  }
 
   if (image_mapping.size() == MAX_RETURN) {
     m_start_after = image_mapping.rbegin()->first;
@@ -135,7 +144,7 @@ template<typename I>
 void LoadRequest<I>::cleanup_image_map() {
   dout(20) << dendl;
 
-  std::set<std::string> map_removals;
+  std::set<GlobalId> map_removals;
 
   auto it = m_image_mapping->begin();
   while (it != m_image_mapping->end()) {
index 9b1be96857aeb0c71758740632040cd405a1bb6a..4d56e18dc79d7a7b96f8d3d750893980ce1e90e0 100644 (file)
@@ -6,6 +6,7 @@
 
 #include "cls/rbd/cls_rbd_types.h"
 #include "include/rados/librados.hpp"
+#include "Types.h"
 
 class Context;
 
@@ -19,7 +20,7 @@ template<typename ImageCtxT = librbd::ImageCtx>
 class LoadRequest {
 public:
   static LoadRequest *create(librados::IoCtx &ioctx,
-                             std::map<std::string, cls::rbd::MirrorImageMap> *image_mapping,
+                             std::map<GlobalId, cls::rbd::MirrorImageMap> *image_mapping,
                              Context *on_finish) {
     return new LoadRequest(ioctx, image_mapping, on_finish);
   }
@@ -47,14 +48,14 @@ private:
    * @endverbatim
    */
   LoadRequest(librados::IoCtx &ioctx,
-              std::map<std::string, cls::rbd::MirrorImageMap> *image_mapping,
+              std::map<GlobalId, cls::rbd::MirrorImageMap> *image_mapping,
               Context *on_finish);
 
   librados::IoCtx &m_ioctx;
-  std::map<std::string, cls::rbd::MirrorImageMap> *m_image_mapping;
+  std::map<GlobalId, cls::rbd::MirrorImageMap> *m_image_mapping;
   Context *m_on_finish;
 
-  std::set<std::string> m_global_image_ids;
+  std::set<GlobalId> m_global_image_ids;
 
   bufferlist m_out_bl;
   std::string m_start_after;
index 88f4f2695496a9a5191dc159306364a2e837e53c..403715f3413e5e41f1bbc8cbc865e837613983a5 100644 (file)
@@ -48,11 +48,11 @@ Policy::Policy(librados::IoCtx &ioctx)
 
   // map should at least have once instance
   std::string instance_id = stringify(ioctx.get_instance_id());
-  m_map.emplace(instance_id, std::set<std::string>{});
+  m_map.emplace(instance_id, GlobalIds{});
 }
 
 void Policy::init(
-    const std::map<std::string, cls::rbd::MirrorImageMap> &image_mapping) {
+    const std::map<GlobalId, cls::rbd::MirrorImageMap> &image_mapping) {
   dout(20) << dendl;
 
   std::unique_lock map_lock{m_map_lock};
@@ -61,8 +61,20 @@ void Policy::init(
     auto map_result = m_map[it.second.instance_id].emplace(it.first);
     ceph_assert(map_result.second);
 
+    PolicyData policy_data;
+    try {
+      auto iter = it.second.data.cbegin();
+      if (!iter.end()) {
+        decode(policy_data, iter);
+      }
+    } catch (const buffer::error &err) {
+      derr << "error decoding policy data: " << err.what() << dendl;
+      continue;
+    }
+
     auto image_state_result = m_image_states.emplace(
-      it.first, ImageState{it.second.instance_id, it.second.mapped_time});
+      it.first, ImageState{policy_data.weight, it.second.instance_id,
+                           it.second.mapped_time});
     ceph_assert(image_state_result.second);
 
     // ensure we (re)send image acquire actions to the instance
@@ -73,40 +85,41 @@ void Policy::init(
   }
 }
 
-LookupInfo Policy::lookup(const std::string &global_image_id) {
-  dout(20) << "global_image_id=" << global_image_id << dendl;
+LookupInfo Policy::lookup(const GlobalId &global_id) {
+  dout(20) << "global_id=" << global_id << dendl;
 
   std::shared_lock map_lock{m_map_lock};
   LookupInfo info;
 
-  auto it = m_image_states.find(global_image_id);
+  auto it = m_image_states.find(global_id);
   if (it != m_image_states.end()) {
     info.instance_id = it->second.instance_id;
     info.mapped_time = it->second.mapped_time;
+    info.weight = it->second.weight;
   }
   return info;
 }
 
-bool Policy::add_image(const std::string &global_image_id) {
-  dout(5) << "global_image_id=" << global_image_id << dendl;
+bool Policy::add_entity(const GlobalId &global_id, uint64_t weight) {
+  dout(5) << "global_id=" << global_id << dendl;
 
   std::unique_lock map_lock{m_map_lock};
-  auto image_state_result = m_image_states.emplace(global_image_id,
-                                                   ImageState{});
+  auto image_state_result = m_image_states.emplace(global_id, ImageState{});
   auto& image_state = image_state_result.first->second;
   if (image_state.state == StateTransition::STATE_INITIALIZING) {
     // avoid duplicate acquire notifications upon leader startup
     return false;
   }
 
+  image_state.weight = weight;
   return set_state(&image_state, StateTransition::STATE_ASSOCIATING, false);
 }
 
-bool Policy::remove_image(const std::string &global_image_id) {
-  dout(5) << "global_image_id=" << global_image_id << dendl;
+bool Policy::remove_entity(const GlobalId &global_id) {
+  dout(5) << "global_id=" << global_id << dendl;
 
   std::unique_lock map_lock{m_map_lock};
-  auto it = m_image_states.find(global_image_id);
+  auto it = m_image_states.find(global_id);
   if (it == m_image_states.end()) {
     return false;
   }
@@ -116,13 +129,13 @@ bool Policy::remove_image(const std::string &global_image_id) {
 }
 
 void Policy::add_instances(const InstanceIds &instance_ids,
-                           GlobalImageIds* global_image_ids) {
+                           GlobalIds* global_ids) {
   dout(5) << "instance_ids=" << instance_ids << dendl;
 
   std::unique_lock map_lock{m_map_lock};
   for (auto& instance : instance_ids) {
     ceph_assert(!instance.empty());
-    m_map.emplace(instance, std::set<std::string>{});
+    m_map.emplace(instance, GlobalIds{});
   }
 
   // post-failover, remove any dead instances and re-shuffle their images
@@ -140,34 +153,41 @@ void Policy::add_instances(const InstanceIds &instance_ids,
     }
 
     if (!dead_instances.empty()) {
-      remove_instances(m_map_lock, dead_instances, global_image_ids);
+      remove_instances(m_map_lock, dead_instances, global_ids);
     }
   }
 
-  GlobalImageIds shuffle_global_image_ids;
-  do_shuffle_add_instances(m_map, m_image_states.size(), &shuffle_global_image_ids);
-  dout(5) << "shuffling global_image_ids=[" << shuffle_global_image_ids
-          << "]" << dendl;
-  for (auto& global_image_id : shuffle_global_image_ids) {
-    auto it = m_image_states.find(global_image_id);
+  GlobalIds shuffle_global_ids;
+  size_t image_count =
+    std::accumulate(m_image_states.begin(), m_image_states.end(), 0,
+                    [](size_t count,
+                       const std::pair<GlobalId, ImageState> &p) {
+                      return count + p.second.weight;
+                    });
+
+  do_shuffle_add_instances(m_map, image_count, &shuffle_global_ids);
+  dout(5) << "shuffling global_ids=[" << shuffle_global_ids << "]" << dendl;
+
+  for (auto &global_id : shuffle_global_ids) {
+    auto it = m_image_states.find(global_id);
     ceph_assert(it != m_image_states.end());
 
     auto& image_state = it->second;
     if (set_state(&image_state, StateTransition::STATE_SHUFFLING, false)) {
-      global_image_ids->emplace(global_image_id);
+      global_ids->emplace(global_id);
     }
   }
 }
 
 void Policy::remove_instances(const InstanceIds &instance_ids,
-                              GlobalImageIds* global_image_ids) {
+                              GlobalIds* global_ids) {
   std::unique_lock map_lock{m_map_lock};
-  remove_instances(m_map_lock, instance_ids, global_image_ids);
+  remove_instances(m_map_lock, instance_ids, global_ids);
 }
 
 void Policy::remove_instances(const ceph::shared_mutex& lock,
                               const InstanceIds &instance_ids,
-                              GlobalImageIds* global_image_ids) {
+                              GlobalIds* global_ids) {
   ceph_assert(ceph_mutex_is_wlocked(m_map_lock));
   dout(5) << "instance_ids=" << instance_ids << dendl;
 
@@ -177,17 +197,17 @@ void Policy::remove_instances(const ceph::shared_mutex& lock,
       continue;
     }
 
-    auto& instance_global_image_ids = map_it->second;
-    if (instance_global_image_ids.empty()) {
+    auto& instance_global_ids = map_it->second;
+    if (instance_global_ids.empty()) {
       m_map.erase(map_it);
       continue;
     }
 
     m_dead_instances.insert(instance_id);
     dout(5) << "force shuffling: instance_id=" << instance_id << ", "
-            << "global_image_ids=[" << instance_global_image_ids << "]"<< dendl;
-    for (auto& global_image_id : instance_global_image_ids) {
-      auto it = m_image_states.find(global_image_id);
+            << "global_ids=[" << instance_global_ids << "]"<< dendl;
+    for (auto& global_id : instance_global_ids) {
+      auto it = m_image_states.find(global_id);
       ceph_assert(it != m_image_states.end());
 
       auto& image_state = it->second;
@@ -198,42 +218,42 @@ void Policy::remove_instances(const ceph::shared_mutex& lock,
       }
 
       if (set_state(&image_state, StateTransition::STATE_SHUFFLING, true)) {
-        global_image_ids->emplace(global_image_id);
+        global_ids->emplace(global_id);
       }
     }
   }
 }
 
-ActionType Policy::start_action(const std::string &global_image_id) {
+ActionType Policy::start_action(const GlobalId &global_id) {
   std::unique_lock map_lock{m_map_lock};
 
-  auto it = m_image_states.find(global_image_id);
+  auto it = m_image_states.find(global_id);
   ceph_assert(it != m_image_states.end());
 
   auto& image_state = it->second;
   auto& transition = image_state.transition;
   ceph_assert(transition.action_type != ACTION_TYPE_NONE);
 
-  dout(5) << "global_image_id=" << global_image_id << ", "
+  dout(5) << "global_id=" << global_id << ", "
           << "state=" << image_state.state << ", "
           << "action_type=" << transition.action_type << dendl;
   if (transition.start_policy_action) {
-    execute_policy_action(global_image_id, &image_state,
+    execute_policy_action(global_id, &image_state,
                           *transition.start_policy_action);
     transition.start_policy_action = boost::none;
   }
   return transition.action_type;
 }
 
-bool Policy::finish_action(const std::string &global_image_id, int r) {
+bool Policy::finish_action(const GlobalId &global_id, int r) {
   std::unique_lock map_lock{m_map_lock};
 
-  auto it = m_image_states.find(global_image_id);
+  auto it = m_image_states.find(global_id);
   ceph_assert(it != m_image_states.end());
 
   auto& image_state = it->second;
   auto& transition = image_state.transition;
-  dout(5) << "global_image_id=" << global_image_id << ", "
+  dout(5) << "global_id=" << global_id << ", "
           << "state=" << image_state.state << ", "
           << "action_type=" << transition.action_type << ", "
           << "r=" << r << dendl;
@@ -265,36 +285,36 @@ bool Policy::finish_action(const std::string &global_image_id, int r) {
   // image state may get purged in execute_policy_action()
   bool pending_action = image_state.transition.action_type != ACTION_TYPE_NONE;
   if (finish_policy_action) {
-    execute_policy_action(global_image_id, &image_state, *finish_policy_action);
+    execute_policy_action(global_id, &image_state, *finish_policy_action);
   }
 
   return pending_action;
 }
 
 void Policy::execute_policy_action(
-    const std::string& global_image_id, ImageState* image_state,
+    const GlobalId &global_id, ImageState *image_state,
     StateTransition::PolicyAction policy_action) {
-  dout(5) << "global_image_id=" << global_image_id << ", "
+  dout(5) << "global_id=" << global_id << ", "
           << "policy_action=" << policy_action << dendl;
 
   switch (policy_action) {
   case StateTransition::POLICY_ACTION_MAP:
-    map(global_image_id, image_state);
+    map(global_id, image_state);
     break;
   case StateTransition::POLICY_ACTION_UNMAP:
-    unmap(global_image_id, image_state);
+    unmap(global_id, image_state);
     break;
   case StateTransition::POLICY_ACTION_REMOVE:
     if (image_state->state == StateTransition::STATE_UNASSOCIATED) {
       ceph_assert(image_state->instance_id == UNMAPPED_INSTANCE_ID);
       ceph_assert(!image_state->next_state);
-      m_image_states.erase(global_image_id);
+      m_image_states.erase(global_id);
     }
     break;
   }
 }
 
-void Policy::map(const std::string& global_image_id, ImageState* image_state) {
+void Policy::map(const GlobalId &global_id, ImageState *image_state) {
   ceph_assert(ceph_mutex_is_wlocked(m_map_lock));
 
   std::string instance_id = image_state->instance_id;
@@ -302,23 +322,22 @@ void Policy::map(const std::string& global_image_id, ImageState* image_state) {
     return;
   }
   if (is_dead_instance(instance_id)) {
-    unmap(global_image_id, image_state);
+    unmap(global_id, image_state);
   }
 
-  instance_id = do_map(m_map, global_image_id);
+  instance_id = do_map(m_map, global_id);
   ceph_assert(!instance_id.empty());
-  dout(5) << "global_image_id=" << global_image_id << ", "
+  dout(5) << "global_id=" << global_id << ", "
           << "instance_id=" << instance_id << dendl;
 
   image_state->instance_id = instance_id;
   image_state->mapped_time = ceph_clock_now();
 
-  auto ins = m_map[instance_id].emplace(global_image_id);
+  auto ins = m_map[instance_id].emplace(global_id);
   ceph_assert(ins.second);
 }
 
-void Policy::unmap(const std::string &global_image_id,
-                   ImageState* image_state) {
+void Policy::unmap(const GlobalId &global_id, ImageState* image_state) {
   ceph_assert(ceph_mutex_is_wlocked(m_map_lock));
 
   std::string instance_id = image_state->instance_id;
@@ -326,11 +345,11 @@ void Policy::unmap(const std::string &global_image_id,
     return;
   }
 
-  dout(5) << "global_image_id=" << global_image_id << ", "
-          << "instance_id=" << instance_id << dendl;
+  dout(5) << "global_id=" << global_id << ", " << "instance_id=" << instance_id
+          << dendl;
 
   ceph_assert(!instance_id.empty());
-  m_map[instance_id].erase(global_image_id);
+  m_map[instance_id].erase(global_id);
   image_state->instance_id = UNMAPPED_INSTANCE_ID;
   image_state->mapped_time = {};
 
@@ -341,29 +360,29 @@ void Policy::unmap(const std::string &global_image_id,
   }
 }
 
-bool Policy::is_image_shuffling(const std::string &global_image_id) {
+bool Policy::is_entity_shuffling(const GlobalId &global_id) const {
   ceph_assert(ceph_mutex_is_locked(m_map_lock));
 
-  auto it = m_image_states.find(global_image_id);
+  auto it = m_image_states.find(global_id);
   ceph_assert(it != m_image_states.end());
   auto& image_state = it->second;
 
   // avoid attempting to re-shuffle a pending shuffle
   auto result = is_state_scheduled(image_state,
                                    StateTransition::STATE_SHUFFLING);
-  dout(20) << "global_image_id=" << global_image_id << ", "
+  dout(20) << "global_id=" << global_id << ", "
            << "result=" << result << dendl;
   return result;
 }
 
-bool Policy::can_shuffle_image(const std::string &global_image_id) {
+bool Policy::can_shuffle_entity(const GlobalId &global_id) const {
   ceph_assert(ceph_mutex_is_locked(m_map_lock));
 
   CephContext *cct = reinterpret_cast<CephContext *>(m_ioctx.cct());
   int migration_throttle = cct->_conf.get_val<uint64_t>(
     "rbd_mirror_image_policy_migration_throttle");
 
-  auto it = m_image_states.find(global_image_id);
+  auto it = m_image_states.find(global_id);
   ceph_assert(it != m_image_states.end());
   auto& image_state = it->second;
 
@@ -374,13 +393,22 @@ bool Policy::can_shuffle_image(const std::string &global_image_id) {
   auto result = (StateTransition::is_idle(image_state.state) &&
                  ((migration_throttle <= 0) ||
                   (now - last_shuffled_time >= migration_throttle)));
-  dout(10) << "global_image_id=" << global_image_id << ", "
+  dout(10) << "global_id=" << global_id << ", "
            << "migration_throttle=" << migration_throttle << ", "
            << "last_shuffled_time=" << last_shuffled_time << ", "
            << "result=" << result << dendl;
   return result;
 }
 
+uint64_t Policy::get_weight(const GlobalId &global_id) const {
+  ceph_assert(ceph_mutex_is_locked(m_map_lock));
+
+  auto it = m_image_states.find(global_id);
+  ceph_assert(it != m_image_states.end());
+
+  return it->second.weight;
+}
+
 bool Policy::set_state(ImageState* image_state, StateTransition::State state,
                        bool ignore_current_state) {
   if (!ignore_current_state && image_state->state == state) {
index 79e825ec193fa474216de1666b89d5db04eccc6b..2e6c5ef9a7db3570e0cd21a8c4640ecc6f31f284 100644 (file)
@@ -30,53 +30,53 @@ public:
   }
 
   // init -- called during initialization
-  void init(
-      const std::map<std::string, cls::rbd::MirrorImageMap> &image_mapping);
+  void init(const std::map<GlobalId, cls::rbd::MirrorImageMap> &image_mapping);
 
   // lookup an image from the map
-  LookupInfo lookup(const std::string &global_image_id);
+  LookupInfo lookup(const GlobalId &global_id);
 
   // add, remove
-  bool add_image(const std::string &global_image_id);
-  bool remove_image(const std::string &global_image_id);
+  bool add_entity(const GlobalId &global_id, uint64_t weight);
+  bool remove_entity(const GlobalId &global_id);
 
   // shuffle images when instances are added/removed
-  void add_instances(const InstanceIds &instance_ids,
-                     GlobalImageIds* global_image_ids);
-  void remove_instances(const InstanceIds &instance_ids,
-                        GlobalImageIds* global_image_ids);
+  void add_instances(const InstanceIds &instance_ids, GlobalIds* global_ids);
+  void remove_instances(const InstanceIds &instance_ids, GlobalIds* global_ids);
 
-  ActionType start_action(const std::string &global_image_id);
-  bool finish_action(const std::string &global_image_id, int r);
+  ActionType start_action(const GlobalId &global_id);
+  bool finish_action(const GlobalId &global_id, int r);
 
 protected:
-  typedef std::map<std::string, std::set<std::string> > InstanceToImageMap;
+  typedef std::map<std::string, GlobalIds> InstanceToImageMap;
 
-  bool is_dead_instance(const std::string instance_id) {
+  bool is_dead_instance(const std::string instance_id) const {
     ceph_assert(ceph_mutex_is_locked(m_map_lock));
     return m_dead_instances.find(instance_id) != m_dead_instances.end();
   }
 
-  bool is_image_shuffling(const std::string &global_image_id);
-  bool can_shuffle_image(const std::string &global_image_id);
+  bool is_entity_shuffling(const GlobalId &global_id) const;
+  bool can_shuffle_entity(const GlobalId &global_id) const;
+  uint64_t get_weight(const GlobalId &global_id) const;
 
-  // map an image (global image id) to an instance
+  // map an entity (global id) to an instance
   virtual std::string do_map(const InstanceToImageMap& map,
-                             const std::string &global_image_id) = 0;
+                             const GlobalId &global_id) = 0;
 
   // shuffle images when instances are added/removed
   virtual void do_shuffle_add_instances(
       const InstanceToImageMap& map, size_t image_count,
-      std::set<std::string> *remap_global_image_ids) = 0;
+      GlobalIds *remap_global_ids) = 0;
 
 private:
   struct ImageState {
+    uint64_t weight = 1;
     std::string instance_id = UNMAPPED_INSTANCE_ID;
     utime_t mapped_time;
 
     ImageState() {}
-    ImageState(const std::string& instance_id, const utime_t& mapped_time)
-      : instance_id(instance_id), mapped_time(mapped_time) {
+    ImageState(uint64_t weight, const std::string& instance_id,
+               const utime_t& mapped_time)
+      : weight(weight), instance_id(instance_id), mapped_time(mapped_time) {
     }
 
     // active state and action
@@ -87,7 +87,7 @@ private:
     boost::optional<StateTransition::State> next_state = boost::none;
   };
 
-  typedef std::map<std::string, ImageState> ImageStates;
+  typedef std::map<GlobalId, ImageState> ImageStates;
 
   librados::IoCtx &m_ioctx;
 
@@ -101,17 +101,16 @@ private:
 
   void remove_instances(const ceph::shared_mutex& lock,
                        const InstanceIds &instance_ids,
-                        GlobalImageIds* global_image_ids);
+                        GlobalIds* global_ids);
 
   bool set_state(ImageState* image_state, StateTransition::State state,
                  bool ignore_current_state);
 
-  void execute_policy_action(const std::string& global_image_id,
-                             ImageState* image_state,
+  void execute_policy_action(const GlobalId& global_id, ImageState* image_state,
                              StateTransition::PolicyAction policy_action);
 
-  void map(const std::string& global_image_id, ImageState* image_state);
-  void unmap(const std::string &global_image_id, ImageState* image_state);
+  void map(const GlobalId &global_id, ImageState* image_state);
+  void unmap(const GlobalId &global_id, ImageState* image_state);
 
   bool is_state_scheduled(const ImageState& image_state,
                           StateTransition::State state) const;
index f26805819e581d89cf419122cd1237135bf36263..c62f799df2928f195ada488fa5cdf486e9788291 100644 (file)
@@ -39,47 +39,63 @@ size_t SimplePolicy::calc_images_per_instance(const InstanceToImageMap& map,
 
 void SimplePolicy::do_shuffle_add_instances(
     const InstanceToImageMap& map, size_t image_count,
-    std::set<std::string> *remap_global_image_ids) {
+    GlobalIds *remap_global_ids) {
   uint64_t images_per_instance = calc_images_per_instance(map, image_count);
   dout(5) << "images per instance=" << images_per_instance << dendl;
 
   for (auto const &instance : map) {
-    if (instance.second.size() <= images_per_instance) {
+    uint64_t instance_image_count =
+      std::accumulate(instance.second.begin(), instance.second.end(), 0,
+                      [this](uint64_t count, const GlobalId &global_id) {
+                        return count + get_weight(global_id);
+                      });
+
+    if (instance_image_count <= images_per_instance) {
       continue;
     }
 
     auto it = instance.second.begin();
-    uint64_t cut_off = instance.second.size() - images_per_instance;
 
+    uint64_t cut_off = instance_image_count - images_per_instance;
+
+    // TODO: improve for weight > 1: find the best entity(ies) to cut off
     while (it != instance.second.end() && cut_off > 0) {
-      if (Policy::is_image_shuffling(*it)) {
-        --cut_off;
-      } else if (Policy::can_shuffle_image(*it)) {
-        --cut_off;
-        remap_global_image_ids->emplace(*it);
+      auto weight = get_weight(*it);
+      if (weight <= cut_off) {
+        if (Policy::is_entity_shuffling(*it)) {
+          cut_off -= weight;
+        } else if (Policy::can_shuffle_entity(*it)) {
+          cut_off -= weight;
+          remap_global_ids->emplace(*it);
+        }
       }
-
       ++it;
     }
   }
 }
 
 std::string SimplePolicy::do_map(const InstanceToImageMap& map,
-                                 const std::string &global_image_id) {
+                                 const GlobalId &global_id) {
   auto min_it = map.end();
+  uint64_t min_image_count = UINT64_MAX;
   for (auto it = map.begin(); it != map.end(); ++it) {
-    ceph_assert(it->second.find(global_image_id) == it->second.end());
+    ceph_assert(it->second.find(global_id) == it->second.end());
     if (Policy::is_dead_instance(it->first)) {
       continue;
-    } else if (min_it == map.end()) {
-      min_it = it;
-    } else if (it->second.size() < min_it->second.size()) {
+    }
+    uint64_t image_count =
+      std::accumulate(it->second.begin(), it->second.end(), 0,
+                      [this](uint64_t count, const GlobalId &global_id) {
+                        return count + get_weight(global_id);
+                      });
+    if (image_count < min_image_count) {
       min_it = it;
+      min_image_count = image_count;
     }
   }
 
   ceph_assert(min_it != map.end());
-  dout(20) << "global_image_id=" << global_image_id << " maps to instance_id="
+  dout(20) << "global_id=" << global_id << " maps to instance_id="
            << min_it->first << dendl;
   return min_it->first;
 }
index ad2071b2cb7a740453b3adce8f24dc8d0f93e31b..4bdf77af0c94e0ca47780c61021f30e7c369640e 100644 (file)
@@ -19,12 +19,12 @@ public:
 protected:
   SimplePolicy(librados::IoCtx &ioctx);
 
-  std::string do_map(const InstanceToImageMapmap,
-                     const std::string &global_image_id) override;
+  std::string do_map(const InstanceToImageMap &map,
+                     const GlobalId &global_id) override;
 
   void do_shuffle_add_instances(
       const InstanceToImageMap& map, size_t image_count,
-      std::set<std::string> *remap_global_image_ids) override;
+      GlobalIds *remap_global_ids) override;
 
 private:
   size_t calc_images_per_instance(const InstanceToImageMap& map,
index 4f5ae6c4966155f18d5f28546ac28655cb987b62..c99029f71c9f2d7050e0e4e00079de93b247d398 100644 (file)
@@ -72,18 +72,41 @@ private:
 
 } // anonymous namespace
 
+GlobalId::GlobalId(const std::string &global_id) {
+  size_t pos = 0;
+  if (global_id.size() > 1 && global_id[1] == ':') {
+    ceph_assert(global_id[0] >= '0');
+    type = static_cast<MirrorEntityType>(global_id[0] - '0');
+    pos = 2;
+  }
+  id = global_id.substr(pos);
+}
+
+std::string GlobalId::to_str() const {
+  if (type == MIRROR_ENTITY_TYPE_IMAGE) {
+    return id;
+  }
+
+  return stringify(static_cast<int>(type)) + ":" + id;
+}
+
+std::ostream &operator<<(std::ostream &os, const GlobalId &global_id) {
+  return os << "{" << global_id.type << ", " << global_id.id << "}";
+}
+
 PolicyMetaType PolicyData::get_policy_meta_type() const {
   return std::visit(GetTypeVisitor<PolicyMetaType>(), policy_meta);
 }
 
 void PolicyData::encode(bufferlist& bl) const {
-  ENCODE_START(1, 1, bl);
+  ENCODE_START(2, 1, bl);
   std::visit(EncodeVisitor(bl), policy_meta);
+  encode(weight, bl);
   ENCODE_FINISH(bl);
 }
 
 void PolicyData::decode(bufferlist::const_iterator& it) {
-  DECODE_START(1, it);
+  DECODE_START(2, it);
 
   uint32_t policy_meta_type;
   decode(policy_meta_type, it);
@@ -98,6 +121,9 @@ void PolicyData::decode(bufferlist::const_iterator& it) {
   }
 
   std::visit(DecodeVisitor(struct_v, it), policy_meta);
+  if (struct_v >= 2) {
+    decode(weight, it);
+  }
   DECODE_FINISH(it);
 }
 
@@ -106,7 +132,7 @@ void PolicyData::dump(Formatter *f) const {
 }
 
 void PolicyData::generate_test_instances(std::list<PolicyData *> &o) {
-  o.push_back(new PolicyData(PolicyMetaNone()));
+  o.push_back(new PolicyData(1, PolicyMetaNone()));
 }
 
 std::ostream &operator<<(std::ostream &os, const ActionType& action_type) {
index 07908dfc7dcab22d755c7bdd81bec3c315437ad1..b68a4674786b0beb4d6ccd18a07f7e2777e9654d 100644 (file)
@@ -46,6 +46,7 @@ struct Listener {
 struct LookupInfo {
   std::string instance_id = UNMAPPED_INSTANCE_ID;
   utime_t mapped_time;
+  uint64_t weight = 1;
 };
 
 enum ActionType {
@@ -56,8 +57,31 @@ enum ActionType {
   ACTION_TYPE_RELEASE
 };
 
+struct GlobalId {
+  MirrorEntityType type = MIRROR_ENTITY_TYPE_IMAGE;
+  std::string id;
+
+  GlobalId(MirrorEntityType type, const std::string &id) : type(type), id(id) {
+  }
+  GlobalId(const std::string &global_id);
+
+  std::string to_str() const;
+
+  inline bool operator==(const GlobalId &rhs) const {
+    return type == rhs.type && id == rhs.id;
+  }
+  inline bool operator<(const GlobalId &rhs) const {
+    if (type != rhs.type) {
+      return type < rhs.type;
+    }
+    return id < rhs.id;
+  }
+};
+
+std::ostream &operator<<(std::ostream &os, const GlobalId &global_id);
+
 typedef std::vector<std::string> InstanceIds;
-typedef std::set<std::string> GlobalImageIds;
+typedef std::set<GlobalId> GlobalIds;
 typedef std::map<std::string, ActionType> ImageActionTypes;
 
 enum PolicyMetaType {
@@ -104,10 +128,11 @@ struct PolicyData {
   PolicyData()
     : policy_meta(PolicyMetaUnknown()) {
   }
-  PolicyData(const PolicyMeta &policy_meta)
-    : policy_meta(policy_meta) {
+  PolicyData(uint64_t weight, const PolicyMeta &policy_meta)
+    : weight(weight), policy_meta(policy_meta) {
   }
 
+  uint64_t weight = 1;
   PolicyMeta policy_meta;
 
   PolicyMetaType get_policy_meta_type() const;
index 799c5670f97d9353b5d959b032b4ee1fabfccab8..689b3be67e7f37b1a2e70b302ecc8b9a78bab5c4 100644 (file)
@@ -26,11 +26,11 @@ static const uint32_t MAX_UPDATE = 256;
 
 template <typename I>
 UpdateRequest<I>::UpdateRequest(librados::IoCtx &ioctx,
-                                std::map<std::string, cls::rbd::MirrorImageMap> &&update_mapping,
-                                std::set<std::string> &&remove_global_image_ids, Context *on_finish)
+                                std::map<GlobalId, cls::rbd::MirrorImageMap> &&update_mapping,
+                                GlobalIds &&remove_global_ids, Context *on_finish)
   : m_ioctx(ioctx),
     m_update_mapping(update_mapping),
-    m_remove_global_image_ids(remove_global_image_ids),
+    m_remove_global_ids(remove_global_ids),
     m_on_finish(on_finish) {
 }
 
@@ -45,7 +45,7 @@ template <typename I>
 void UpdateRequest<I>::update_image_map() {
   dout(20) << dendl;
 
-  if (m_update_mapping.empty() && m_remove_global_image_ids.empty()) {
+  if (m_update_mapping.empty() && m_remove_global_ids.empty()) {
     finish(0);
     return;
   }
@@ -55,14 +55,14 @@ void UpdateRequest<I>::update_image_map() {
 
   auto it1 = m_update_mapping.begin();
   while (it1 != m_update_mapping.end() && nr_updates++ < MAX_UPDATE) {
-    librbd::cls_client::mirror_image_map_update(&op, it1->first, it1->second);
+    librbd::cls_client::mirror_image_map_update(&op, it1->first.to_str(), it1->second);
     it1 = m_update_mapping.erase(it1);
   }
 
-  auto it2 = m_remove_global_image_ids.begin();
-  while (it2 != m_remove_global_image_ids.end() && nr_updates++ < MAX_UPDATE) {
-    librbd::cls_client::mirror_image_map_remove(&op, *it2);
-    it2 = m_remove_global_image_ids.erase(it2);
+  auto it2 = m_remove_global_ids.begin();
+  while (it2 != m_remove_global_ids.end() && nr_updates++ < MAX_UPDATE) {
+    librbd::cls_client::mirror_image_map_remove(&op, it2->to_str());
+    it2 = m_remove_global_ids.erase(it2);
   }
 
   librados::AioCompletion *aio_comp = create_rados_callback<
index 841cc6f9bd597444750ff7f82bcc12ac2dc12361..5b871cdef3610985af1200d1d56f17fd1fbc5b98 100644 (file)
@@ -6,6 +6,7 @@
 
 #include "cls/rbd/cls_rbd_types.h"
 #include "include/rados/librados.hpp"
+#include "Types.h"
 
 class Context;
 
@@ -21,9 +22,9 @@ public:
   // accepts an image map for updation and a collection of
   // global image ids to purge.
   static UpdateRequest *create(librados::IoCtx &ioctx,
-                               std::map<std::string, cls::rbd::MirrorImageMap> &&update_mapping,
-                               std::set<std::string> &&remove_global_image_ids, Context *on_finish) {
-    return new UpdateRequest(ioctx, std::move(update_mapping), std::move(remove_global_image_ids),
+                               std::map<GlobalId, cls::rbd::MirrorImageMap> &&update_mapping,
+                               GlobalIds &&remove_global_ids, Context *on_finish) {
+    return new UpdateRequest(ioctx, std::move(update_mapping), std::move(remove_global_ids),
                              on_finish);
   }
 
@@ -44,12 +45,12 @@ private:
    * @endverbatim
    */
   UpdateRequest(librados::IoCtx &ioctx,
-                std::map<std::string, cls::rbd::MirrorImageMap> &&update_mapping,
-                std::set<std::string> &&remove_global_image_ids, Context *on_finish);
+                std::map<GlobalId, cls::rbd::MirrorImageMap> &&update_mapping,
+                GlobalIds &&remove_global_ids, Context *on_finish);
 
   librados::IoCtx &m_ioctx;
-  std::map<std::string, cls::rbd::MirrorImageMap> m_update_mapping;
-  std::set<std::string> m_remove_global_image_ids;
+  std::map<GlobalId, cls::rbd::MirrorImageMap> m_update_mapping;
+  GlobalIds m_remove_global_ids;
   Context *m_on_finish;
 
   void update_image_map();
diff --git a/src/tools/rbd_mirror/pool_watcher/RefreshEntitiesRequest.cc b/src/tools/rbd_mirror/pool_watcher/RefreshEntitiesRequest.cc
new file mode 100644 (file)
index 0000000..25d84d4
--- /dev/null
@@ -0,0 +1,89 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#include "tools/rbd_mirror/pool_watcher/RefreshEntitiesRequest.h"
+#include "common/debug.h"
+#include "common/errno.h"
+#include "cls/rbd/cls_rbd_client.h"
+#include "librbd/Utils.h"
+#include <map>
+
+#define dout_context g_ceph_context
+#define dout_subsys ceph_subsys_rbd_mirror
+#undef dout_prefix
+#define dout_prefix *_dout << "rbd::mirror::pool_watcher::RefreshEntitiesRequest " \
+                           << this << " " << __func__ << ": "
+
+namespace rbd {
+namespace mirror {
+namespace pool_watcher {
+
+static const uint32_t MAX_RETURN = 1024;
+
+using librbd::util::create_rados_callback;
+
+template <typename I>
+void RefreshEntitiesRequest<I>::send() {
+  m_entities->clear();
+  mirror_image_list();
+}
+
+template <typename I>
+void RefreshEntitiesRequest<I>::mirror_image_list() {
+  dout(10) << dendl;
+
+  librados::ObjectReadOperation op;
+  librbd::cls_client::mirror_image_list_start(&op, m_start_after, MAX_RETURN,
+                                              false);
+  m_out_bl.clear();
+  librados::AioCompletion *aio_comp = create_rados_callback<
+    RefreshEntitiesRequest<I>,
+    &RefreshEntitiesRequest<I>::handle_mirror_image_list>(this);
+  int r = m_remote_io_ctx.aio_operate(RBD_MIRRORING, aio_comp, &op, &m_out_bl);
+  ceph_assert(r == 0);
+  aio_comp->release();
+}
+
+template <typename I>
+void RefreshEntitiesRequest<I>::handle_mirror_image_list(int r) {
+  dout(10) << "r=" << r << dendl;
+
+  std::map<std::string, std::string> ids;
+  if (r == 0) {
+    auto it = m_out_bl.cbegin();
+    r = librbd::cls_client::mirror_image_list_finish(&it, &ids);
+  }
+
+  if (r < 0 && r != -ENOENT) {
+    derr << "failed to list mirrored images: " << cpp_strerror(r) << dendl;
+    finish(r);
+    return;
+  }
+
+  for (auto &[image_id, global_image_id] : ids) {
+    m_entities->insert(
+        {{MIRROR_ENTITY_TYPE_IMAGE, global_image_id, 1}, image_id});
+  }
+
+  if (ids.size() == MAX_RETURN) {
+    m_start_after = ids.rbegin()->first;
+    mirror_image_list();
+    return;
+  }
+
+  finish(0);
+}
+
+template <typename I>
+void RefreshEntitiesRequest<I>::finish(int r) {
+  dout(10) << "r=" << r << dendl;
+
+  m_on_finish->complete(r);
+  delete this;
+}
+
+} // namespace pool_watcher
+} // namespace mirror
+} // namespace rbd
+
+template class rbd::mirror::pool_watcher::RefreshEntitiesRequest<librbd::ImageCtx>;
diff --git a/src/tools/rbd_mirror/pool_watcher/RefreshEntitiesRequest.h b/src/tools/rbd_mirror/pool_watcher/RefreshEntitiesRequest.h
new file mode 100644 (file)
index 0000000..ab1957a
--- /dev/null
@@ -0,0 +1,77 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#ifndef CEPH_RBD_MIRROR_POOL_WATCHER_REFRESH_IMAGES_REQUEST_H
+#define CEPH_RBD_MIRROR_POOL_WATCHER_REFRESH_IMAGES_REQUEST_H
+
+#include "include/buffer.h"
+#include "include/rados/librados.hpp"
+#include "tools/rbd_mirror/Types.h"
+#include <string>
+
+struct Context;
+
+namespace librbd { struct ImageCtx; }
+
+namespace rbd {
+namespace mirror {
+namespace pool_watcher {
+
+template <typename ImageCtxT = librbd::ImageCtx>
+class RefreshEntitiesRequest {
+public:
+  static RefreshEntitiesRequest *create(librados::IoCtx &remote_io_ctx,
+                                        std::map<MirrorEntity,
+                                        std::string> *entities,
+                                        Context *on_finish) {
+    return new RefreshEntitiesRequest(remote_io_ctx, entities, on_finish);
+  }
+
+  RefreshEntitiesRequest(librados::IoCtx &remote_io_ctx,
+                         std::map<MirrorEntity,
+                         std::string> *entities,
+                         Context *on_finish)
+    : m_remote_io_ctx(remote_io_ctx), m_entities(entities),
+      m_on_finish(on_finish) {
+  }
+
+  void send();
+
+private:
+  /**
+   * @verbatim
+   *
+   * <start>
+   *    |
+   *    |   /-------------\
+   *    |   |             |
+   *    v   v             | (more images)
+   * MIRROR_IMAGE_LIST ---/
+   *    |
+   *    v
+   * <finish>
+   *
+   * @endverbatim
+   */
+
+  librados::IoCtx &m_remote_io_ctx;
+  std::map<MirrorEntity, std::string> *m_entities;
+  Context *m_on_finish;
+
+  bufferlist m_out_bl;
+  std::string m_start_after;
+
+  void mirror_image_list();
+  void handle_mirror_image_list(int r);
+
+  void finish(int r);
+
+};
+
+} // namespace pool_watcher
+} // namespace mirror
+} // namespace rbd
+
+extern template class rbd::mirror::pool_watcher::RefreshEntitiesRequest<librbd::ImageCtx>;
+
+#endif // CEPH_RBD_MIRROR_POOL_WATCHER_REFRESH_IMAGES_REQUEST_H
diff --git a/src/tools/rbd_mirror/pool_watcher/RefreshImagesRequest.cc b/src/tools/rbd_mirror/pool_watcher/RefreshImagesRequest.cc
deleted file mode 100644 (file)
index 7448ba4..0000000
+++ /dev/null
@@ -1,89 +0,0 @@
-// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
-// vim: ts=8 sw=2 smarttab
-
-#include "tools/rbd_mirror/pool_watcher/RefreshImagesRequest.h"
-#include "common/debug.h"
-#include "common/errno.h"
-#include "cls/rbd/cls_rbd_client.h"
-#include "librbd/Utils.h"
-#include <map>
-
-#define dout_context g_ceph_context
-#define dout_subsys ceph_subsys_rbd_mirror
-#undef dout_prefix
-#define dout_prefix *_dout << "rbd::mirror::pool_watcher::RefreshImagesRequest " \
-                           << this << " " << __func__ << ": "
-
-namespace rbd {
-namespace mirror {
-namespace pool_watcher {
-
-static const uint32_t MAX_RETURN = 1024;
-
-using librbd::util::create_rados_callback;
-
-template <typename I>
-void RefreshImagesRequest<I>::send() {
-  m_image_ids->clear();
-  mirror_image_list();
-}
-
-template <typename I>
-void RefreshImagesRequest<I>::mirror_image_list() {
-  dout(10) << dendl;
-
-  librados::ObjectReadOperation op;
-  librbd::cls_client::mirror_image_list_start(&op, m_start_after, MAX_RETURN,
-                                              false);
-  m_out_bl.clear();
-  librados::AioCompletion *aio_comp = create_rados_callback<
-    RefreshImagesRequest<I>,
-    &RefreshImagesRequest<I>::handle_mirror_image_list>(this);
-  int r = m_remote_io_ctx.aio_operate(RBD_MIRRORING, aio_comp, &op, &m_out_bl);
-  ceph_assert(r == 0);
-  aio_comp->release();
-}
-
-template <typename I>
-void RefreshImagesRequest<I>::handle_mirror_image_list(int r) {
-  dout(10) << "r=" << r << dendl;
-
-  std::map<std::string, std::string> ids;
-  if (r == 0) {
-    auto it = m_out_bl.cbegin();
-    r = librbd::cls_client::mirror_image_list_finish(&it, &ids);
-  }
-
-  if (r < 0 && r != -ENOENT) {
-    derr << "failed to list mirrored images: " << cpp_strerror(r) << dendl;
-    finish(r);
-    return;
-  }
-
-  // store as global -> local image ids
-  for (auto &id : ids) {
-    m_image_ids->emplace(id.second, id.first);
-  }
-
-  if (ids.size() == MAX_RETURN) {
-    m_start_after = ids.rbegin()->first;
-    mirror_image_list();
-    return;
-  }
-
-  finish(0);
-}
-
-template <typename I>
-void RefreshImagesRequest<I>::finish(int r) {
-  dout(10) << "r=" << r << dendl;
-
-  m_on_finish->complete(r);
-  delete this;
-}
-
-} // namespace pool_watcher
-} // namespace mirror
-} // namespace rbd
-
-template class rbd::mirror::pool_watcher::RefreshImagesRequest<librbd::ImageCtx>;
diff --git a/src/tools/rbd_mirror/pool_watcher/RefreshImagesRequest.h b/src/tools/rbd_mirror/pool_watcher/RefreshImagesRequest.h
deleted file mode 100644 (file)
index 8bfeabe..0000000
+++ /dev/null
@@ -1,73 +0,0 @@
-// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
-// vim: ts=8 sw=2 smarttab
-
-#ifndef CEPH_RBD_MIRROR_POOL_WATCHER_REFRESH_IMAGES_REQUEST_H
-#define CEPH_RBD_MIRROR_POOL_WATCHER_REFRESH_IMAGES_REQUEST_H
-
-#include "include/buffer.h"
-#include "include/rados/librados.hpp"
-#include "tools/rbd_mirror/Types.h"
-#include <string>
-
-struct Context;
-
-namespace librbd { struct ImageCtx; }
-
-namespace rbd {
-namespace mirror {
-namespace pool_watcher {
-
-template <typename ImageCtxT = librbd::ImageCtx>
-class RefreshImagesRequest {
-public:
-  static RefreshImagesRequest *create(librados::IoCtx &remote_io_ctx,
-                                      ImageIds *image_ids, Context *on_finish) {
-    return new RefreshImagesRequest(remote_io_ctx, image_ids, on_finish);
-  }
-
-  RefreshImagesRequest(librados::IoCtx &remote_io_ctx, ImageIds *image_ids,
-                       Context *on_finish)
-    : m_remote_io_ctx(remote_io_ctx), m_image_ids(image_ids),
-      m_on_finish(on_finish) {
-  }
-
-  void send();
-
-private:
-  /**
-   * @verbatim
-   *
-   * <start>
-   *    |
-   *    |   /-------------\
-   *    |   |             |
-   *    v   v             | (more images)
-   * MIRROR_IMAGE_LIST ---/
-   *    |
-   *    v
-   * <finish>
-   *
-   * @endverbatim
-   */
-
-  librados::IoCtx &m_remote_io_ctx;
-  ImageIds *m_image_ids;
-  Context *m_on_finish;
-
-  bufferlist m_out_bl;
-  std::string m_start_after;
-
-  void mirror_image_list();
-  void handle_mirror_image_list(int r);
-
-  void finish(int r);
-
-};
-
-} // namespace pool_watcher
-} // namespace mirror
-} // namespace rbd
-
-extern template class rbd::mirror::pool_watcher::RefreshImagesRequest<librbd::ImageCtx>;
-
-#endif // CEPH_RBD_MIRROR_POOL_WATCHER_REFRESH_IMAGES_REQUEST_H
index 52dfc342dd4d8b0815a3047a785145977d4dfe6d..81e14be8c901568515097caeda9cfef9d54a8c7a 100644 (file)
@@ -16,8 +16,8 @@ struct Listener {
   }
 
   virtual void handle_update(const std::string &mirror_uuid,
-                             ImageIds &&added_image_ids,
-                             ImageIds &&removed_image_ids) = 0;
+                             MirrorEntities &&added_entities,
+                             MirrorEntities &&removed_entities) = 0;
 };
 
 } // namespace pool_watcher