George
08/20/2022, 12:13 PMGeorge
08/20/2022, 12:15 PMmcpiroman
08/20/2022, 12:17 PMGeorge
08/20/2022, 12:22 PMoverride fun trySelectOther(otherOp: PrepareOp?): Any? {
_state.loop { state -> // lock-free loop on state
when {
// Found initial state (not selected yet) -- try to make it selected
state === NOT_SELECTED -> {
if (otherOp == null) {
// regular trySelect -- just mark as select
if (!_state.compareAndSet(NOT_SELECTED, null)) return@loop
} else {
// Rendezvous with another select instance -- install PairSelectOp
val pairSelectOp = PairSelectOp(otherOp)
if (!_state.compareAndSet(NOT_SELECTED, pairSelectOp)) return@loop
val decision = pairSelectOp.perform(this)
if (decision !== null) return decision
}
doAfterSelect()
return RESUME_TOKEN
}
state is OpDescriptor -> { // state is either AtomicSelectOp or PairSelectOp
// Found descriptor of ongoing operation while working in the context of other select operation
if (otherOp != null) {
val otherAtomicOp = otherOp.atomicOp
when {
// It is the same select instance
otherAtomicOp is AtomicSelectOp && otherAtomicOp.impl === this -> {
/*
* We cannot do state.perform(this) here and "help" it since it is the same
* select and we'll get StackOverflowError.
* See <https://github.com/Kotlin/kotlinx.coroutines/issues/1411>
* We cannot support this because select { ... } is an expression and its clauses
* have a result that shall be returned from the select.
*/
error("Cannot use matching select clauses on the same object")
}
// The other select (that is trying to proceed) had started earlier
otherAtomicOp.isEarlierThan(state) -> {
/**
* Abort to prevent deadlock by returning a failure to it.
* See <https://github.com/Kotlin/kotlinx.coroutines/issues/504>
* The other select operation will receive a failure and will restart itself with a
* larger sequence number. This guarantees obstruction-freedom of this algorithm.
*/
return RETRY_ATOMIC
}
}
}
// Otherwise (not a special descriptor)
state.perform(this) // help it
}
// otherwise -- already selected
otherOp == null -> return null // already selected
state === otherOp.desc -> return RESUME_TOKEN // was selected with this marker
else -> return null // selected with different marker
}
}
}
George
08/20/2022, 12:24 PMoverride suspend fun replaceMasterDevice(input: NewMasterDevice, client: Client): HubPayload<Int> {
if (input.isNotRegistrationIdValid()) return badRequest()
val masterDevice = input.toDevice()
val registrationId = masterDevice.registrationId
val currentMasterDevice = staleDeviceServiceRepoService.getCurrentMasterDevice(masterDevice.accountUuid)
?: return notRegisteredError(input.accountUuid)
// maybe return something more specific here?
if (currentMasterDevice.registrationId.compareTo(registrationId) == 0) return badRequest()
val server = serverRepoService.getServer(client)
val newMasterDevice = masterDevice.toDeviceEntity(MASTER_DEVICE_ID, server.id, true)
val newStaleDeviceId = staleDeviceServiceRepoService.replaceMasterDevice(newMasterDevice)
return dataPayload(newStaleDeviceId)
}
This could have been better if it was with no break lines?
override suspend fun replaceMasterDevice(input: NewMasterDevice, client: Client): HubPayload<Int> {
if (input.isNotRegistrationIdValid()) return badRequest()
val masterDevice = input.toDevice()
val registrationId = masterDevice.registrationId
val currentMasterDevice = staleDeviceServiceRepoService.getCurrentMasterDevice(masterDevice.accountUuid)
?: return notRegisteredError(input.accountUuid)
// maybe return something more specific here?
if (currentMasterDevice.registrationId.compareTo(registrationId) == 0) return badRequest()
val server = serverRepoService.getServer(client)
val newMasterDevice = masterDevice.toDeviceEntity(MASTER_DEVICE_ID, server.id, true)
val newStaleDeviceId = staleDeviceServiceRepoService.replaceMasterDevice(newMasterDevice)
return dataPayload(newStaleDeviceId)
}
mcpiroman
08/20/2022, 12:33 PMGeorge
08/20/2022, 12:46 PMprivate fun ensureCapacity() {
val currentSize = elements.size
val newCapacity = currentSize shl 1
val newElements = arrayOfNulls<Any>(newCapacity)
elements.copyInto(
destination = newElements,
startIndex = head
)
elements.copyInto(
destination = newElements,
destinationOffset = elements.size - head,
endIndex = head
)
elements = newElements
head = 0
tail = currentSize
}
If it were me i would put some spaces after the vals at least (maybe?) i guess there is some thought behind it or i am reading into it too much?