Import document docid - document key body - marshalled body of document to be imported isDelete - whether the document to be imported is a delete existingDoc - bytes/cas/expiry of the document to be imported (including xattr when available) mode - ImportMode - ImportFromFeed or ImportOnDeman
(ctx context.Context, docid string, body Body, expiry *uint32, isDelete bool, revNo uint64, existingDoc *sgbucket.BucketDocument, mode ImportMode)
| 122 | // existingDoc - bytes/cas/expiry of the document to be imported (including xattr when available) |
| 123 | // mode - ImportMode - ImportFromFeed or ImportOnDemand |
| 124 | func (db *DatabaseCollectionWithUser) importDoc(ctx context.Context, docid string, body Body, expiry *uint32, isDelete bool, revNo uint64, existingDoc *sgbucket.BucketDocument, mode ImportMode) (docOut *Document, err error) { |
| 125 | |
| 126 | base.DebugfCtx(ctx, base.KeyImport, "Attempting to import doc %q...", base.UD(docid)) |
| 127 | importStartTime := time.Now() |
| 128 | |
| 129 | if existingDoc == nil { |
| 130 | return nil, base.RedactErrorf("No existing doc present when attempting to import %s", base.UD(docid)) |
| 131 | } else if body == nil { |
| 132 | if !isDelete { |
| 133 | // only deletes can have an empty (null) body and be imported |
| 134 | return nil, base.ErrEmptyDocument |
| 135 | } |
| 136 | body = Body{} |
| 137 | } |
| 138 | |
| 139 | newDoc := &Document{ |
| 140 | ID: docid, |
| 141 | Deleted: isDelete, |
| 142 | } |
| 143 | |
| 144 | var newRev string |
| 145 | var alreadyImportedDoc *Document |
| 146 | |
| 147 | mutationOptions := &sgbucket.MutateInOptions{} |
| 148 | if db.dataStore.IsSupported(sgbucket.BucketStoreFeaturePreserveExpiry) { |
| 149 | mutationOptions.PreserveExpiry = true |
| 150 | } else { |
| 151 | // Get the doc expiry if it wasn't passed in and preserve expiry is not supported |
| 152 | if expiry == nil { |
| 153 | getExpiry, getExpiryErr := db.dataStore.GetExpiry(ctx, docid) |
| 154 | if getExpiryErr != nil { |
| 155 | return nil, getExpiryErr |
| 156 | } |
| 157 | expiry = &getExpiry |
| 158 | } |
| 159 | existingDoc.Expiry = *expiry |
| 160 | } |
| 161 | |
| 162 | docUpdateEvent := Import |
| 163 | // do not update rev cache for any imports (CBG-4494 and CBG-4550) |
| 164 | const updateRevCache = false |
| 165 | docOut, _, err = db.updateAndReturnDoc(ctx, newDoc.ID, true, expiry, mutationOptions, docUpdateEvent, existingDoc, true, updateRevCache, func(doc *Document) (resultDocument *Document, resultAttachmentData updatedAttachments, createNewRevIDSkipped bool, updatedExpiry *uint32, resultErr error) { |
| 166 | // Perform cas mismatch check first, as we want to identify cas mismatch before triggering migrate handling. |
| 167 | // If there's a cas mismatch, the doc has been updated since the version that triggered the import. Handling depends on import mode. |
| 168 | if doc.Cas != existingDoc.Cas { |
| 169 | // If this is a feed import, cancel on cas failure (doc has been updated ) |
| 170 | if mode == ImportFromFeed { |
| 171 | return nil, nil, false, nil, base.ErrImportCasFailure |
| 172 | } |
| 173 | |
| 174 | // If this is an on-demand import, we want to continue to import the current version of the doc. Re-initialize existing doc based on the latest doc |
| 175 | if mode == ImportOnDemand { |
| 176 | body = doc.Body(ctx) |
| 177 | if body == nil { |
| 178 | return nil, nil, false, nil, base.ErrEmptyDocument |
| 179 | } |
| 180 | |
| 181 | existingDoc = &sgbucket.BucketDocument{ |