[Bug]: Replication result depends on whether the target has a validate_doc_update function
Los mantenedores suelen responder en 1 día
Nadie ha tomado este issue todavía.
Evaluación
- Dificultad
- 4/5
- Tiempo estimado
- 3-5 días
- Aptitud para principiantes
- 44/100
- Tipo de issue
- Error
- Claridad
- Bastante claro
- Estado de actividad
- Activo
- Stack tecnológico
- erlang, javascript
- Área
- database, databases, distributed-systems
Línea de trabajo
Start with couch_db:before_docs_update and prep_and_validate_replicated_updates, then trace how couch_replicator_worker:find_missing handles the missing ratio. Run the provided curl and jq reproduction against CouchDB 3.5.3 and compare the final document in t1 and t2. Done means both targets reach the same document state with and without the accepting validate_doc_update design doc.
Escrito por el modelo de indexación a partir del texto del issue.
Descripción
Version
3.5.3
Describe the problem you're encountering
Two target databases that get the same replications, in the same order, from the same sources can end up with a different state for a document: one ends deleted, the other ends live with an old revision as the winner. The only difference between the targets is a design doc whose validate_doc_update accepts everything.
It shows up when a target first receives a revision with a short history (from a replica with a low revs_limit) and later receives the same revision again with its full history.
Expected Behaviour
I would expect replication to give the same result whether or not the target has a validate_doc_update function that accepts the document.
Steps to Reproduce
Needs curl and jq. Single node, one-shot _replicate, run in order.
COUCH=http://adm:[email protected]:5984
J='Content-Type: application/json'
for db in a c b d t1 t2; do curl -sS -X PUT "$COUCH/$db" > /dev/null; done
curl -sS -X PUT "$COUCH/b/_revs_limit" -d 1 > /dev/null
curl -sS -X PUT "$COUCH/d/_revs_limit" -d 2 > /dev/null
curl -sS -X PUT "$COUCH/t2/_design/accept" -H "$J" \
-d '{"validate_doc_update":"function(newDoc, oldDoc, userCtx, secObj) {}"}' > /dev/null
rep() { curl -sS -X POST "$COUCH/_replicate" -H "$J" \
-d "{\"source\":\"$COUCH/$1\",\"target\":\"$COUCH/$2\"${3:+,$3}}" > /dev/null; }
ONLY_X='"doc_ids":["X"]'
# create X (1-a) on a, replicate to c
REV=$(curl -sS -X PUT "$COUCH/a/X" -H "$J" -d '{"v":"a"}' | jq -r .rev)
rep a c "$ONLY_X"
# 6 unrelated docs on a
curl -sS -X POST "$COUCH/a/_bulk_docs" -H "$J" -d '{"docs":[
{"_id":"f1"},{"_id":"f2"},{"_id":"f3"},{"_id":"f4"},{"_id":"f5"},{"_id":"f6"}]}' > /dev/null
# edit X (2-b) on a, replicate to b (revs_limit 1, so b keeps 2-b with no ancestors)
REV=$(curl -sS -X PUT "$COUCH/a/X" -H "$J" -d "{\"_rev\":\"$REV\",\"v\":\"b\"}" | jq -r .rev)
rep a b "$ONLY_X"
# both targets: c then b, giving two separate roots 1-a and 2-b
for t in t1 t2; do rep c $t; rep b $t; done
# both targets: replicate a with one worker, batch size 1
for t in t1 t2; do rep a $t '"worker_processes":1,"worker_batch_size":1'; done
# delete X (3-d) on a, replicate to d (revs_limit 2), then d to both targets
curl -sS -X DELETE "$COUCH/a/X?rev=$REV" > /dev/null
rep a d "$ONLY_X"
for t in t1 t2; do rep d $t; done
curl -sS "$COUCH/t1/X"
curl -sS "$COUCH/t2/X"
Output on 3.5.3:
{"error":"not_found","reason":"deleted"}
{"_id":"X","_rev":"1-cd6dcd82d939d5b6220025fbc573b36a","v":"a"}
Your Environment
CouchDB 3.5.3 (git 7a1f97558), Erlang/OTP 28, single node, q=1 n=1, macOS arm64.
Additional Context
From reading the source, I think two things interact:
couch_db:before_docs_updateonly runsprep_and_validate_replicated_updateswhen the db has a VDU (or a design doc or attachments in the request). That step drops a replicated revision that is already a leaf; without a VDU the same path gets merged.couch_replicator_worker:find_missingskips_revs_diffonce the missing ratio average goes over 0.95 (6 batches in a row where everything was missing), and then re-sends revisions the target already has, with the longer history.
The same split happens with default replication settings when 20,000 unrelated docs come before X in a's changes. If the unrelated docs come after X, or there are only 5, both targets end the same. The relevant files look unchanged on main.
Fuller repro with all runs and controls: https://github.com/blackwell-systems/normalization-confluence/tree/main/research/couchdb-replicator
- Lenguaje dominante
- Erlang
- Estrellas
- 7k
- Forks
- 1.1k
- Merge medio
- 10 h 16 min
- PR fusionados (30 d)
- 35
Preparar el entorno
Inicia el contenedor de desarrollo del proyecto en tu navegador, con tu propia cuenta de GitHub.
- Sin Dockerfile ni archivo de Docker Compose
- Tiene una plantilla de pull request
- Leer la guía de contribución
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Más de apache/couchdb
-
Dificultad 3/5 1-2 días Aptitud para principiantes 45/100
Los mantenedores suelen responder en 1 día
-
Fix: Warning: 'catch ...' is deprecated; please use 'try ... catch ... end' insteadQuizá libre de nuevo @devx-arjun la tomó hace 8 días y no hay ningún pull request abierto. Abiertobeginner-friendly build chore patches-welcome
Dificultad 4/5 3-5 días Aptitud para principiantes 45/100
apache/couchdb#6144 · 4 comentarios ·
Los mantenedores suelen responder en 1 día
-
bug needs-triage
Dificultad 4/5 3-5 días Aptitud para principiantes 48/100
apache/couchdb#6132 · 3 comentarios ·
Los mantenedores suelen responder en 1 día
-
[ENHANCEMENT]: Add seq checkpoints to continuous feedsPosiblemente ocupada @nickva la tomó hace 1 día. Abiertoenhancement
Dificultad 5/5 Más de una semana Aptitud para principiantes 45/100
apache/couchdb#6120 · 7 comentarios ·
Los mantenedores suelen responder en 1 día
-
enhancement needs-triage
Dificultad 3/5 1-2 días Aptitud para principiantes 55/100
Los mantenedores suelen responder en 1 día
Todos los issues de apache/couchdb
Issues similares
-
draft
Dificultad 2/5 1-3 horas Aptitud para principiantes 66/100
Los mantenedores suelen responder en 1 día
-
DefaultRedisList.get(int) does not reject an index equal to the list sizePosiblemente ocupada @ryujungkyun la tomó hoy. Abiertostatus: waiting-for-triage
Dificultad 1/5 Menos de una hora Aptitud para principiantes 68/100
spring-projects/spring-data-redis#3471 ·
Los mantenedores suelen responder en 5 días
-
Dificultad 1/5 Menos de una hora Aptitud para principiantes 82/100
mozilla/experimenter#17757 ·
Los mantenedores suelen responder en 1 día
-
Database backend cleanup can delete task results before result_expires with non-UTC timezonesPosiblemente ocupada @Namraa310806 la tomó hoy. AbiertoComponent: SQLAlchemy Database Results Backend Issue Type: Bug Report
Dificultad 2/5 1-3 horas Aptitud para principiantes 68/100
celery/celery#10865 · 2 comentarios ·
Los mantenedores suelen responder en 1 día
-
C-bug O-community X-blathers-untriaged
Dificultad 2/5 1-3 horas Aptitud para principiantes 72/100
cockroachdb/cockroach#176136 · 1 comentario ·
Los mantenedores suelen responder en 12 días