in common/scala/src/main/scala/org/apache/openwhisk/core/database/cosmosdb/CosmosDBArtifactStore.scala [99:155]
override protected[database] def put(d: DocumentAbstraction)(implicit transid: TransactionId): Future[DocInfo] = {
val asJson = d.toDocumentRecord
val (doc, docSize) = toCosmosDoc(asJson)
val id = doc.getId
val docinfoStr = s"id: $id, rev: ${doc.getETag}"
val start = transid.started(this, LoggingMarkers.DATABASE_SAVE, s"[PUT] '$collName' saving document: '$docinfoStr'")
val o = if (isNewDocument(doc)) {
client.createDocument(collection.getSelfLink, doc, newRequestOption(id), true)
} else {
client.replaceDocument(doc, matchRevOption(id, doc.getETag))
}
val f = o
.head()
.recoverWith {
case e: DocumentClientException if isConflict(e) && isNewDocument(doc) =>
val docId = DocId(asJson.fields(_id).convertTo[String])
//Fetch existing document and check if its deleted
getRaw(docId).flatMap {
case Some(js) =>
if (isSoftDeleted(js)) {
//Existing document is soft deleted. So can be replaced. Use the etag of document
//and replace it with document we are trying to add
val etag = js.fields(Properties.E_TAG).convertTo[String]
client.replaceDocument(doc, matchRevOption(id, etag)).head()
} else {
//Trying to create a new document and found an existing
//Document which is valid (not soft delete) then conflict is a valid outcome
throw e
}
case None =>
//Document not found. Should not happen unless someone else removed
//Propagate existing exception
throw e
}
}
.transform(
{ r =>
docSizeToken.histogram.record(docSize)
transid.finished(
this,
start,
s"[PUT] '$collName' completed document: '$docinfoStr', size=$docSize, ru=${r.getRequestCharge}${extraLogs(r)}",
InfoLevel)
collectMetrics(putToken, r.getRequestCharge)
toDocInfo(r.getResource)
}, {
case e: DocumentClientException if isConflict(e) =>
transid.finished(this, start, s"[PUT] '$collName', document: '$docinfoStr'; conflict.")
DocumentConflictException("conflict on 'put'")
case e => e
})
reportFailure(f, start, failure => s"[PUT] '$collName' internal error, failure: '${failure.getMessage}'")
}