Skip to content

Commit bb9386c

Browse files
authored
bug fix: delete vertices processor may core, if this vertex also have edges and index (#2335)
* delete vertices may core, if this vertex also have edges and index * different tagId will use the same vertexPrefix, so can not break if iterator an edge
1 parent b548c74 commit bb9386c

File tree

3 files changed

+106
-9
lines changed

3 files changed

+106
-9
lines changed

src/common/utils/NebulaKeyUtils.h

+2-5
Original file line numberDiff line numberDiff line change
@@ -137,11 +137,8 @@ class NebulaKeyUtils final {
137137
msg << " rawKey.size() != kVertexLen."
138138
<< "\nrawKey.size()=" << rawKey.size()
139139
<< "\nkVertexLen=" << kVertexLen
140-
<< "\nrawkey string format=" << rawKey
141-
<< "\nrawkey dec format:";
142-
for (auto i = 0U; i != rawKey.size(); ++i) {
143-
msg << "\nrawKey[" << i << "]=" << static_cast<int>(rawKey[i]);
144-
}
140+
<< "\nhexDump:\n"
141+
<< folly::hexDump(rawKey.data(), rawKey.size());
145142
LOG(FATAL) << msg.str();
146143
}
147144
auto offset = sizeof(PartitionID) + sizeof(VertexID);

src/storage/mutate/DeleteVerticesProcessor.cpp

+6-4
Original file line numberDiff line numberDiff line change
@@ -95,12 +95,14 @@ DeleteVerticesProcessor::deleteVertices(GraphSpaceID spaceId,
9595
TagID latestVVId = -1;
9696
while (iter->valid()) {
9797
auto key = iter->key();
98+
if (!NebulaKeyUtils::isVertex(key)) {
99+
iter->next();
100+
continue;
101+
}
98102
auto tagId = NebulaKeyUtils::getTagId(key);
99103
if (FLAGS_enable_vertex_cache && vertexCache_ != nullptr) {
100-
if (NebulaKeyUtils::isVertex(key)) {
101-
VLOG(3) << "Evict vertex cache for vertex ID " << vertex << ", tagId " << tagId;
102-
vertexCache_->evict(std::make_pair(vertex, tagId));
103-
}
104+
VLOG(3) << "Evict vertex cache for vertex ID " << vertex << ", tagId " << tagId;
105+
vertexCache_->evict(std::make_pair(vertex, tagId));
104106
}
105107

106108
/**

src/storage/test/DeleteVerticesTest.cpp

+98
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@
1010
#include "fs/TempDir.h"
1111
#include "storage/test/TestUtils.h"
1212
#include "storage/mutate/DeleteVerticesProcessor.h"
13+
#include "storage/mutate/DeleteEdgesProcessor.h"
1314
#include "storage/mutate/AddVerticesProcessor.h"
15+
#include "storage/mutate/AddEdgesProcessor.h"
1416
#include "utils/NebulaKeyUtils.h"
1517

1618

@@ -90,6 +92,102 @@ TEST(DeleteVerticesTest, SimpleTest) {
9092
}
9193
}
9294

95+
TEST(DeleteVerticesTest, DeleteVerticesMayCoreIfThereAreEdges) {
96+
fs::TempDir rootPath("/tmp/DeleteVertexTest.XXXXXX");
97+
std::unique_ptr<kvstore::KVStore> kv(TestUtils::initKV(rootPath.path()));
98+
auto schemaMan = TestUtils::mockSchemaMan();
99+
auto indexMan = TestUtils::mockIndexMan();
100+
// Add vertices
101+
{
102+
auto* processor = AddVerticesProcessor::instance(kv.get(),
103+
schemaMan.get(),
104+
indexMan.get(),
105+
nullptr);
106+
cpp2::AddVerticesRequest req;
107+
req.space_id = 0;
108+
req.overwritable = false;
109+
// partId => List<Vertex>
110+
for (PartitionID partId = 0; partId < 3; partId++) {
111+
auto vertices = TestUtils::setupVertices(partId, partId * 10, 10 * (partId + 1));
112+
req.parts.emplace(partId, std::move(vertices));
113+
}
114+
115+
auto fut = processor->getFuture();
116+
processor->process(req);
117+
auto resp = std::move(fut).get();
118+
EXPECT_EQ(0, resp.result.failed_codes.size());
119+
120+
for (PartitionID partId = 0; partId < 3; partId++) {
121+
for (VertexID vertexId = 10 * partId; vertexId < 10 * (partId + 1); vertexId++) {
122+
auto prefix = NebulaKeyUtils::vertexPrefix(partId, vertexId);
123+
std::unique_ptr<kvstore::KVIterator> iter;
124+
EXPECT_EQ(kvstore::ResultCode::SUCCEEDED, kv->prefix(0, partId, prefix, &iter));
125+
TagID tagId = 0;
126+
while (iter->valid()) {
127+
EXPECT_EQ(TestUtils::encodeValue(partId, vertexId, tagId), iter->val());
128+
tagId++;
129+
iter->next();
130+
}
131+
EXPECT_EQ(10, tagId);
132+
}
133+
}
134+
}
135+
136+
// Add edges
137+
{
138+
auto* processor = AddEdgesProcessor::instance(kv.get(),
139+
schemaMan.get(),
140+
indexMan.get(),
141+
nullptr);
142+
cpp2::AddEdgesRequest req;
143+
req.space_id = 0;
144+
req.overwritable = true;
145+
for (PartitionID partId = 1; partId <= 3; partId++) {
146+
auto edges = TestUtils::setupEdges(partId, partId * 10, 10 * (partId + 1));
147+
req.parts.emplace(partId, std::move(edges));
148+
}
149+
150+
auto fut = processor->getFuture();
151+
processor->process(req);
152+
auto resp = std::move(fut).get();
153+
EXPECT_EQ(0, resp.result.failed_codes.size());
154+
}
155+
156+
// Delete vertices
157+
{
158+
cpp2::DeleteVerticesRequest req;
159+
req.set_space_id(0);
160+
for (PartitionID partId = 0; partId < 3; partId++) {
161+
std::vector<VertexID> vertices;
162+
for (VertexID vertexId = 10 * partId; vertexId < 10 * (partId + 1); vertexId++) {
163+
vertices.emplace_back(vertexId);
164+
}
165+
req.parts.emplace(partId, std::move(vertices));
166+
}
167+
168+
auto* processor = DeleteVerticesProcessor::instance(kv.get(),
169+
schemaMan.get(),
170+
indexMan.get(),
171+
nullptr);
172+
173+
// pretend there are some index
174+
175+
auto fut = processor->getFuture();
176+
processor->process(req);
177+
auto resp = std::move(fut).get();
178+
EXPECT_EQ(0, resp.result.failed_codes.size());
179+
}
180+
181+
for (PartitionID partId = 0; partId < 3; partId++) {
182+
for (VertexID vertexId = 10 * partId; vertexId < 10 * (partId + 1); vertexId++) {
183+
auto prefix = NebulaKeyUtils::vertexPrefix(partId, vertexId);
184+
std::unique_ptr<kvstore::KVIterator> iter;
185+
EXPECT_EQ(kvstore::ResultCode::SUCCEEDED, kv->prefix(0, partId, prefix, &iter));
186+
CHECK(!NebulaKeyUtils::isVertex(iter->key()));
187+
}
188+
}
189+
}
190+
93191
} // namespace storage
94192
} // namespace nebula
95193

0 commit comments

Comments
 (0)