【发布时间】:2017-07-17 14:35:47
【问题描述】:
我想修改编译最新的mongodb源代码(截至目前,mongodb版本v3.5.10-34-g27d21e6 from github)使_id字段不自动生成如果插入文档时未提供。当前官方发布的 mongodb 需要存在这个字段(我已经在 mongodb-win32-x86_64-v3.4-latest from https://www.mongodb.org 上测试过这个事实)。
我发现了一个相关问题Mongodb inserting doc without _id field。但我认为我的问题与这个问题不重复,因为我的问题是要求修改源代码,而这个问题是关于参数设置(其答案也不再适用于当前版本的 mongodb)。
我知道官方的mongodb组有他们的理由和考虑要求这样一个_id字段,既然他们已经决定引入这样的要求,他们不太可能会在不久的将来删除它未来。而且我也知道禁用 _id 会影响 mongodb 的某些功能,例如上面提到的复制。但我仍然想知道如何禁用它,因为我只是将它用作个人数据库,在一台机器上只运行一个实例。我确信我不需要其他功能。存储是我考虑最多的,所以我不希望这个字段占用额外的磁盘空间。出于同样的原因,我需要具有压缩能力的 WiredTiger 引擎,所以我需要对相对较新的 mongodb 版本执行此操作。
到目前为止,我已经使用安装了VS2015的scons成功编译并链接了原始源代码v3.5.10-34-g27d21e6。所以我希望有人能告诉我应该修改哪些源代码文件/文件的哪些代码段/段以禁用自动生成 _id 字段;以及哪些文件也需要“修补”,以检查 _id 的存在,如果找不到,即使它们并不真正需要它也会拒绝正常工作。
我发现以下两个文件似乎相关:
1) mongo/src/mongo/db/ops/insert.cpp 行:153-177
我尝试如下修改这个文件,但之后 _id 仍然是自动创建的
来自:
if (firstElementIsId) {
b.append(doc.firstElement());
i.next();
} else {
BSONElement e = doc["_id"];
if (e.type()) {
b.append(e);
} else {
b.appendOID("_id", NULL, true);
}
}
while (i.more()) {
BSONElement e = i.next();
if (hadId && e.fieldNameStringData() == "_id") {
// no-op
} else if (e.type() == bsonTimestamp && e.timestampValue() == 0) {
auto nextTime = LogicalClock::get(service)->reserveTicks(1);
b.append(e.fieldName(), nextTime.asTimestamp());
} else {
b.append(e);
}
}
到:
if (firstElementIsId) {
//b.append(doc.firstElement());
i.next();
} else {
BSONElement e = doc["_id"];
if (e.type()) {
//b.append(e);
} else {
//b.appendOID("_id", NULL, true);
}
}
while (i.more()) {
BSONElement e = i.next();
if (hadId && e.fieldNameStringData() == "_id") {
// no-op
} else if (e.fieldNameStringData() == "_id") {
// no-op
} else if (e.type() == bsonTimestamp && e.timestampValue() == 0) {
auto nextTime = LogicalClock::get(service)->reserveTicks(1);
b.append(e.fieldName(), nextTime.asTimestamp());
} else {
b.append(e);
}
}
2) mongo/src/mongo/bson/bsonobj.cpp 行:281-315
我没有修改这个文件,因为我没有看到哪一行代码可以添加 _id 字段,只是感觉它可能与它在评论中提到的问题有关。
/* note: addFields always adds _id even if not specified
returns n added not counting _id unless requested.
*/
int BSONObj::addFields(BSONObj& from, set<string>& fields) {
verify(isEmpty() && !isOwned()); /* partial implementation for now... */
BSONObjBuilder b;
int N = fields.size();
int n = 0;
BSONObjIterator i(from);
bool gotId = false;
while (i.moreWithEOO()) {
BSONElement e = i.next();
const char* fname = e.fieldName();
if (fields.count(fname)) {
b.append(e);
++n;
gotId = gotId || strcmp(fname, "_id") == 0;
if (n == N && gotId)
break;
} else if (strcmp(fname, "_id") == 0) {
b.append(e);
gotId = true;
if (n == N && gotId)
break;
}
}
if (n) {
*this = b.obj();
}
return n;
}
所以,这就是我现在所做的。 我不熟悉 mongodb 源代码结构,这对我来说确实是一个巨大的项目。期待一份详细的待办事项列表,我可以按照它来修改代码,而无需太多关于 mongodb 工作原理的知识。但是,当然,欢迎提供任何其他类型的相关信息。提前致谢。
【问题讨论】:
-
根据您提到的相关问题,插入文档时可以覆盖默认的
_id值。你破解服务器代码的目的是什么?这似乎是一条很长的路,可能会节省一些字节,并且除非您彻底测试,否则可能会导致细微的损坏。如果您要进行更改,我建议使用稳定分支 (v3.4) 而不是开发分支 (v3.5 / master)。如果您喜欢 WiredTiger 但不想要分布式数据库或查询计划器的好处/开销,您也可以考虑直接使用WiredTiger library。 -
@Stennie 关于节省的空间: 是的,对于每个文档,可能只能节省几个字节。但在我的情况下,每个文档本身通常都很短,_id 字段仍然占据不可忽略的容量比例,并且会随着添加大量文档而累积。由于这是供个人使用,我不能像公司那样添加更多磁盘,而且我的 PC 上的磁盘空间已经不足。所以我只想通过压缩来压缩磁盘空间,并尽可能地删除不必要的字段。
-
@Stennie 关于难度: 我对mongodb的源码不熟悉,对这个hacking的难度没有明确的认识。我希望源代码设计得如此周到,以至于会有一些神奇的开关等着我去发现,它们可以很容易地做到这一点,只有我不熟悉代码才能轻松找到它/它们.我仍然希望是这样。
-
@Stennie 关于版本: 是的,我同意,v3.4 会更好,我会试试的,谢谢你的提示。 关于WiredTiger,我认为你的推荐对我很有吸引力,因为它最能满足我的要求。但是考虑到学习如何使用 WiredTiger 库进行编程所需的难度和时间投入,除了它支持压缩和行级锁定之外,我目前对此一无所知,我认为修补 Mongodb 的一些代码对我来说似乎相对更可取和实用.但我会开门的,谢谢你的信息。
-
为什么不重命名您已经使用“_id”的现有字段之一(然后在创建集合时确保_id 上不存在唯一索引)?