feat: cleanup returning availability (#650)
Co-authored-by: markspanbroek <mark@spanbroek.net>
This commit is contained in:
parent
0c3d1dd563
commit
e62cb96bde
|
@ -109,6 +109,7 @@ proc remove(sales: Sales, agent: SalesAgent) {.async.} =
|
||||||
|
|
||||||
proc cleanUp(sales: Sales,
|
proc cleanUp(sales: Sales,
|
||||||
agent: SalesAgent,
|
agent: SalesAgent,
|
||||||
|
returnBytes: bool,
|
||||||
processing: Future[void]) {.async.} =
|
processing: Future[void]) {.async.} =
|
||||||
|
|
||||||
let data = agent.data
|
let data = agent.data
|
||||||
|
@ -119,9 +120,19 @@ proc cleanUp(sales: Sales,
|
||||||
reservationId = data.reservation.?id |? ReservationId.default,
|
reservationId = data.reservation.?id |? ReservationId.default,
|
||||||
availabilityId = data.reservation.?availabilityId |? AvailabilityId.default
|
availabilityId = data.reservation.?availabilityId |? AvailabilityId.default
|
||||||
|
|
||||||
# TODO: return bytes that were used in the request back to the availability
|
# if reservation for the SalesAgent was not created, then it means
|
||||||
# as well, which will require removing the bytes from disk (perhaps via
|
# that the cleanUp was called before the sales process really started, so
|
||||||
# setting blockTTL to -1 and then running block maintainer?)
|
# there are not really any bytes to be returned
|
||||||
|
if returnBytes and request =? data.request and reservation =? data.reservation:
|
||||||
|
if returnErr =? (await sales.context.reservations.returnBytesToAvailability(
|
||||||
|
reservation.availabilityId,
|
||||||
|
reservation.id,
|
||||||
|
request.ask.slotSize
|
||||||
|
)).errorOption:
|
||||||
|
error "failure returning bytes",
|
||||||
|
error = returnErr.msg,
|
||||||
|
availabilityId = reservation.availabilityId,
|
||||||
|
bytes = request.ask.slotSize
|
||||||
|
|
||||||
# delete reservation and return reservation bytes back to the availability
|
# delete reservation and return reservation bytes back to the availability
|
||||||
if reservation =? data.reservation and
|
if reservation =? data.reservation and
|
||||||
|
@ -164,8 +175,8 @@ proc processSlot(sales: Sales, item: SlotQueueItem, done: Future[void]) =
|
||||||
none StorageRequest
|
none StorageRequest
|
||||||
)
|
)
|
||||||
|
|
||||||
agent.onCleanUp = proc {.async.} =
|
agent.onCleanUp = proc (returnBytes = false) {.async.} =
|
||||||
await sales.cleanUp(agent, done)
|
await sales.cleanUp(agent, returnBytes, done)
|
||||||
|
|
||||||
agent.onFilled = some proc(request: StorageRequest, slotIndex: UInt256) =
|
agent.onFilled = some proc(request: StorageRequest, slotIndex: UInt256) =
|
||||||
sales.filled(request, slotIndex, done)
|
sales.filled(request, slotIndex, done)
|
||||||
|
@ -229,9 +240,9 @@ proc load*(sales: Sales) {.async.} =
|
||||||
slot.slotIndex,
|
slot.slotIndex,
|
||||||
some slot.request)
|
some slot.request)
|
||||||
|
|
||||||
agent.onCleanUp = proc {.async.} =
|
agent.onCleanUp = proc(returnBytes = false) {.async.} =
|
||||||
let done = newFuture[void]("onCleanUp_Dummy")
|
let done = newFuture[void]("onCleanUp_Dummy")
|
||||||
await sales.cleanUp(agent, done)
|
await sales.cleanUp(agent, returnBytes, done)
|
||||||
await done # completed in sales.cleanUp
|
await done # completed in sales.cleanUp
|
||||||
|
|
||||||
agent.start(SaleUnknown())
|
agent.start(SaleUnknown())
|
||||||
|
|
|
@ -359,6 +359,58 @@ proc createReservation*(
|
||||||
|
|
||||||
return success(reservation)
|
return success(reservation)
|
||||||
|
|
||||||
|
proc returnBytesToAvailability*(
|
||||||
|
self: Reservations,
|
||||||
|
availabilityId: AvailabilityId,
|
||||||
|
reservationId: ReservationId,
|
||||||
|
bytes: UInt256): Future[?!void] {.async.} =
|
||||||
|
|
||||||
|
logScope:
|
||||||
|
reservationId
|
||||||
|
availabilityId
|
||||||
|
|
||||||
|
|
||||||
|
without key =? key(reservationId, availabilityId), error:
|
||||||
|
return failure(error)
|
||||||
|
|
||||||
|
without var reservation =? (await self.get(key, Reservation)), error:
|
||||||
|
return failure(error)
|
||||||
|
|
||||||
|
# We are ignoring bytes that are still present in the Reservation because
|
||||||
|
# they will be returned to Availability through `deleteReservation`.
|
||||||
|
let bytesToBeReturned = bytes - reservation.size
|
||||||
|
|
||||||
|
if bytesToBeReturned == 0:
|
||||||
|
trace "No bytes are returned", requestSizeBytes = bytes, returningBytes = bytesToBeReturned
|
||||||
|
return success()
|
||||||
|
|
||||||
|
trace "Returning bytes", requestSizeBytes = bytes, returningBytes = bytesToBeReturned
|
||||||
|
|
||||||
|
# First lets see if we can re-reserve the bytes, if the Repo's quota
|
||||||
|
# is depleted then we will fail-fast as there is nothing to be done atm.
|
||||||
|
if reserveErr =? (await self.repo.reserve(bytesToBeReturned.truncate(uint))).errorOption:
|
||||||
|
return failure(reserveErr.toErr(ReserveFailedError))
|
||||||
|
|
||||||
|
without availabilityKey =? availabilityId.key, error:
|
||||||
|
return failure(error)
|
||||||
|
|
||||||
|
without var availability =? await self.get(availabilityKey, Availability), error:
|
||||||
|
return failure(error)
|
||||||
|
|
||||||
|
availability.size += bytesToBeReturned
|
||||||
|
|
||||||
|
# Update availability with returned size
|
||||||
|
if updateErr =? (await self.update(availability)).errorOption:
|
||||||
|
|
||||||
|
trace "Rolling back returning bytes"
|
||||||
|
if rollbackErr =? (await self.repo.release(bytesToBeReturned.truncate(uint))).errorOption:
|
||||||
|
rollbackErr.parent = updateErr
|
||||||
|
return failure(rollbackErr)
|
||||||
|
|
||||||
|
return failure(updateErr)
|
||||||
|
|
||||||
|
return success()
|
||||||
|
|
||||||
proc release*(
|
proc release*(
|
||||||
self: Reservations,
|
self: Reservations,
|
||||||
reservationId: ReservationId,
|
reservationId: ReservationId,
|
||||||
|
|
|
@ -25,7 +25,7 @@ type
|
||||||
onCleanUp*: OnCleanUp
|
onCleanUp*: OnCleanUp
|
||||||
onFilled*: ?OnFilled
|
onFilled*: ?OnFilled
|
||||||
|
|
||||||
OnCleanUp* = proc: Future[void] {.gcsafe, upraises: [].}
|
OnCleanUp* = proc (returnBytes = false): Future[void] {.gcsafe, upraises: [].}
|
||||||
OnFilled* = proc(request: StorageRequest,
|
OnFilled* = proc(request: StorageRequest,
|
||||||
slotIndex: UInt256) {.gcsafe, upraises: [].}
|
slotIndex: UInt256) {.gcsafe, upraises: [].}
|
||||||
|
|
||||||
|
|
|
@ -29,6 +29,6 @@ method run*(state: SaleCancelled, machine: Machine): Future[?State] {.async.} =
|
||||||
onClear(request, data.slotIndex)
|
onClear(request, data.slotIndex)
|
||||||
|
|
||||||
if onCleanUp =? agent.onCleanUp:
|
if onCleanUp =? agent.onCleanUp:
|
||||||
await onCleanUp()
|
await onCleanUp(returnBytes = true)
|
||||||
|
|
||||||
warn "Sale cancelled due to timeout", requestId = $data.requestId, slotIndex = $data.slotIndex
|
warn "Sale cancelled due to timeout", requestId = $data.requestId, slotIndex = $data.slotIndex
|
||||||
|
|
|
@ -29,5 +29,5 @@ method run*(state: SaleErrored, machine: Machine): Future[?State] {.async.} =
|
||||||
onClear(request, data.slotIndex)
|
onClear(request, data.slotIndex)
|
||||||
|
|
||||||
if onCleanUp =? agent.onCleanUp:
|
if onCleanUp =? agent.onCleanUp:
|
||||||
await onCleanUp()
|
await onCleanUp(returnBytes = true)
|
||||||
|
|
||||||
|
|
|
@ -175,6 +175,24 @@ asyncchecksuite "Reservations module":
|
||||||
let updated = !(await reservations.get(key, Availability))
|
let updated = !(await reservations.get(key, Availability))
|
||||||
check updated.size == orig
|
check updated.size == orig
|
||||||
|
|
||||||
|
test "calling returnBytesToAvailability returns bytes back to availability":
|
||||||
|
let availability = createAvailability()
|
||||||
|
let reservation = createReservation(availability)
|
||||||
|
let orig = availability.size - reservation.size
|
||||||
|
let origQuota = repo.quotaReservedBytes
|
||||||
|
let returnedBytes = reservation.size + 200.u256
|
||||||
|
|
||||||
|
check isOk await reservations.returnBytesToAvailability(
|
||||||
|
reservation.availabilityId, reservation.id, returnedBytes
|
||||||
|
)
|
||||||
|
|
||||||
|
let key = availability.key.get
|
||||||
|
let updated = !(await reservations.get(key, Availability))
|
||||||
|
|
||||||
|
check updated.size > orig
|
||||||
|
check (updated.size - orig) == 200.u256
|
||||||
|
check (repo.quotaReservedBytes - origQuota) == 200
|
||||||
|
|
||||||
test "reservation can be partially released":
|
test "reservation can be partially released":
|
||||||
let availability = createAvailability()
|
let availability = createAvailability()
|
||||||
let reservation = createReservation(availability)
|
let reservation = createReservation(availability)
|
||||||
|
|
|
@ -149,6 +149,7 @@ asyncchecksuite "Sales":
|
||||||
|
|
||||||
let me = await market.getSigner()
|
let me = await market.getSigner()
|
||||||
market.activeSlots[me] = @[]
|
market.activeSlots[me] = @[]
|
||||||
|
market.requestEnds[request.id] = request.expiry.toSecondsSince1970
|
||||||
|
|
||||||
clock = MockClock.new()
|
clock = MockClock.new()
|
||||||
let repoDs = SQLiteDatastore.new(Memory).tryGet()
|
let repoDs = SQLiteDatastore.new(Memory).tryGet()
|
||||||
|
@ -169,7 +170,6 @@ asyncchecksuite "Sales":
|
||||||
sales.onProve = proc(slot: Slot, challenge: ProofChallenge): Future[seq[byte]] {.async.} =
|
sales.onProve = proc(slot: Slot, challenge: ProofChallenge): Future[seq[byte]] {.async.} =
|
||||||
return proof
|
return proof
|
||||||
await sales.start()
|
await sales.start()
|
||||||
request.expiry = (clock.now() + 42).u256
|
|
||||||
itemsProcessed = @[]
|
itemsProcessed = @[]
|
||||||
|
|
||||||
teardown:
|
teardown:
|
||||||
|
|
Loading…
Reference in New Issue