Processes a "rev" request, i.e. client is pushing a revision body stats must always be provided, along with all the fields filled with valid pointers
(rq *blip.Message, stats *processRevStats)
| 1029 | // Processes a "rev" request, i.e. client is pushing a revision body |
| 1030 | // stats must always be provided, along with all the fields filled with valid pointers |
| 1031 | func (bh *blipHandler) processRev(rq *blip.Message, stats *processRevStats) (err error) { |
| 1032 | startTime := time.Now() |
| 1033 | defer func() { |
| 1034 | stats.processingTime.Add(time.Since(startTime).Nanoseconds()) |
| 1035 | if err == nil { |
| 1036 | stats.count.Add(1) |
| 1037 | } else { |
| 1038 | stats.errorCount.Add(1) |
| 1039 | } |
| 1040 | }() |
| 1041 | |
| 1042 | if bh.db.DatabaseContext.Options.UnsupportedOptions != nil && bh.db.DatabaseContext.Options.UnsupportedOptions.RejectWritesWithSkippedSequences { |
| 1043 | // if we are in slow broadcast mode reject write with 503 and increment rejected writes stat |
| 1044 | if bh.db.BroadcastSlowMode.Load() { |
| 1045 | bh.db.DbStats.DatabaseStats.NumDocWritesRejected.Add(1) |
| 1046 | return base.HTTPErrorf(http.StatusServiceUnavailable, "Database cache is behind and cannot accept writes at this time. Please try again later.") |
| 1047 | } |
| 1048 | } |
| 1049 | |
| 1050 | // throttle concurrent revs |
| 1051 | if cap(bh.inFlightRevsThrottle) > 0 { |
| 1052 | select { |
| 1053 | case bh.inFlightRevsThrottle <- struct{}{}: |
| 1054 | default: |
| 1055 | stats.throttledRevs.Add(1) |
| 1056 | throttleStart := time.Now() |
| 1057 | bh.inFlightRevsThrottle <- struct{}{} |
| 1058 | stats.throttledRevTime.Add(time.Since(throttleStart).Nanoseconds()) |
| 1059 | } |
| 1060 | defer func() { <-bh.inFlightRevsThrottle }() |
| 1061 | } |
| 1062 | |
| 1063 | // addRevisionParams := newAddRevisionParams(rq) |
| 1064 | revMessage := RevMessage{Message: rq} |
| 1065 | |
| 1066 | // Doc metadata comes from the BLIP message metadata, not magic document properties: |
| 1067 | docID, found := revMessage.ID() |
| 1068 | rev, rfound := revMessage.Rev() |
| 1069 | if !found || !rfound { |
| 1070 | return base.HTTPErrorf(http.StatusBadRequest, "Missing docID or rev") |
| 1071 | } |
| 1072 | |
| 1073 | if bh.readOnly { |
| 1074 | return base.HTTPErrorf(http.StatusForbidden, "Replication context is read-only, docID: %s, rev:%s", docID, rev) |
| 1075 | } |
| 1076 | |
| 1077 | base.DebugfCtx(bh.loggingCtx, base.KeySyncMsg, "#%d: Type:%s %s", bh.serialNumber, rq.Profile(), revMessage.String()) |
| 1078 | |
| 1079 | bodyBytes, err := rq.Body() |
| 1080 | if err != nil { |
| 1081 | return err |
| 1082 | } |
| 1083 | |
| 1084 | base.TracefCtx(bh.loggingCtx, base.KeySyncMsg, "#%d: Properties:%v Body:%s", bh.serialNumber, base.UD(revMessage.Properties), base.UD(string(bodyBytes))) |
| 1085 | |
| 1086 | stats.bytes.Add(int64(len(bodyBytes))) |
| 1087 | |
| 1088 | if bh.BlipSyncContext.purgeOnRemoval && bytes.Contains(bodyBytes, []byte(`"`+BodyRemoved+`":`)) { |
no test coverage detected