sync: # file upload improve
This commit is contained in:
parent
9041abd3d3
commit
e70bb0f167
6 changed files with 489 additions and 31 deletions
|
|
@ -42,6 +42,7 @@ const (
|
|||
// 32-MiB per-connection budget and therefore remains admissible by default.
|
||||
layerRPCAdmissionStaticObjectBytes = 512
|
||||
layerRPCAdmissionWireFactor = 60
|
||||
layerRPCAdmissionFlatBytesFactor = 2
|
||||
layerRPCAdmissionGraphSlack = layerRPCAdmissionStaticObjectBytes * 32
|
||||
)
|
||||
|
||||
|
|
@ -164,33 +165,91 @@ func (s *Server) initialLayerRPCAdmissionCursor(ctx context.Context, c *Conn) (l
|
|||
// Saturation deliberately turns hostile integer-sized inputs into ordinary
|
||||
// capacity rejection; it must never wrap into a small accepted reservation.
|
||||
func layerRPCAdmissionReservationSize(wireBytes int) int {
|
||||
return saturatingLayerRPCAdmissionCharge(
|
||||
layerRPCAdmissionGraphSlack,
|
||||
layerRPCAdmissionWireCharge(wireBytes),
|
||||
)
|
||||
}
|
||||
|
||||
func layerRPCAdmissionWireCharge(wireBytes int) int {
|
||||
if wireBytes < 0 {
|
||||
wireBytes = 0
|
||||
}
|
||||
maxInt := int(^uint(0) >> 1)
|
||||
if wireBytes > (maxInt-layerRPCAdmissionGraphSlack)/layerRPCAdmissionWireFactor {
|
||||
if wireBytes > maxInt/layerRPCAdmissionWireFactor {
|
||||
return maxInt
|
||||
}
|
||||
return wireBytes*layerRPCAdmissionWireFactor + layerRPCAdmissionGraphSlack
|
||||
return wireBytes * layerRPCAdmissionWireFactor
|
||||
}
|
||||
|
||||
// layerRPCFlatBytesWireCharge keeps the generic factor on fixed TL wire and
|
||||
// applies a tight copy factor only to a payload which the production Router has
|
||||
// already proven to be one bounded flat bytes field. The temporary expanded
|
||||
// buffer remains independently owned by inboundFrameBudget while generated
|
||||
// admission materializes the request; 2x covers the retained bytes copy plus
|
||||
// allocator rounding without treating every payload byte as a possible nested
|
||||
// object/vector node. The per-request graph slack is owned by the base
|
||||
// reservation and must not be repeated for each nested gzip expansion.
|
||||
func layerRPCFlatBytesWireCharge(wireBytes, payloadBytes int) int {
|
||||
if wireBytes < 0 || payloadBytes < 0 || payloadBytes > wireBytes {
|
||||
return layerRPCAdmissionWireCharge(wireBytes)
|
||||
}
|
||||
fixedBytes := wireBytes - payloadBytes
|
||||
maxInt := int(^uint(0) >> 1)
|
||||
if fixedBytes > maxInt/layerRPCAdmissionWireFactor {
|
||||
return maxInt
|
||||
}
|
||||
charge := fixedBytes * layerRPCAdmissionWireFactor
|
||||
if payloadBytes > (maxInt-charge)/layerRPCAdmissionFlatBytesFactor {
|
||||
return maxInt
|
||||
}
|
||||
return charge + payloadBytes*layerRPCAdmissionFlatBytesFactor
|
||||
}
|
||||
|
||||
func saturatingLayerRPCAdmissionCharge(left, right int) int {
|
||||
if left < 0 {
|
||||
left = 0
|
||||
}
|
||||
if right < 0 {
|
||||
right = 0
|
||||
}
|
||||
maxInt := int(^uint(0) >> 1)
|
||||
if right > maxInt-left {
|
||||
return maxInt
|
||||
}
|
||||
return left + right
|
||||
}
|
||||
|
||||
func (s *Server) layerRPCExpandedWireCharge(wire []byte) int {
|
||||
if s != nil {
|
||||
if sizer, ok := s.layerRPC.(LayerRPCFlatBytesPayloadSizer); ok {
|
||||
if payloadBytes, flat := sizer.LayerRPCFlatBytesPayloadSize(wire); flat && payloadBytes >= 0 && payloadBytes <= len(wire) {
|
||||
return layerRPCFlatBytesWireCharge(len(wire), payloadBytes)
|
||||
}
|
||||
}
|
||||
}
|
||||
return layerRPCAdmissionWireCharge(len(wire))
|
||||
}
|
||||
|
||||
// layerRPCGZIPExpansionBudget bridges transient process-wide expansion memory
|
||||
// to the durable scheduler charge of one exact typed request. sourceBytes is
|
||||
// conservative: it retains the original compressed wire plus every successful
|
||||
// expansion seen across nested envelopes or an authoritative-profile re-decode.
|
||||
// to the durable scheduler charge of one exact typed request. The original
|
||||
// compressed wire retains the generic graph charge. Every successful expansion
|
||||
// adds its own charge; only a handler-proven flat bytes terminal can use the
|
||||
// tighter payload factor. An authoritative-profile re-decode reuses the largest
|
||||
// already-held charge instead of double-counting sequential attempts.
|
||||
type layerRPCGZIPExpansionBudget struct {
|
||||
server *Server
|
||||
plan *inboundPlan
|
||||
reservation *inboundRPCBatchReservation
|
||||
entry int
|
||||
baseSourceBytes int
|
||||
attemptExpandedBytes int
|
||||
chargedSourceBytes int
|
||||
server *Server
|
||||
plan *inboundPlan
|
||||
reservation *inboundRPCBatchReservation
|
||||
entry int
|
||||
baseCharge int
|
||||
attemptExpandedCharge int
|
||||
chargedSize int
|
||||
}
|
||||
|
||||
func (b *layerRPCGZIPExpansionBudget) beginAttempt() {
|
||||
if b != nil {
|
||||
b.attemptExpandedBytes = 0
|
||||
b.attemptExpandedCharge = 0
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -221,17 +280,19 @@ func (b *layerRPCGZIPExpansionBudget) expand(wire []byte, admissionLimit int) ([
|
|||
return nil, release, err
|
||||
}
|
||||
b.plan.gzipExpandedBytes += len(data)
|
||||
b.attemptExpandedBytes += len(data)
|
||||
targetSourceBytes := b.baseSourceBytes + b.attemptExpandedBytes
|
||||
targetCharge := layerRPCAdmissionReservationSize(targetSourceBytes)
|
||||
if targetSourceBytes > b.chargedSourceBytes {
|
||||
b.attemptExpandedCharge = saturatingLayerRPCAdmissionCharge(
|
||||
b.attemptExpandedCharge,
|
||||
b.server.layerRPCExpandedWireCharge(data),
|
||||
)
|
||||
targetCharge := saturatingLayerRPCAdmissionCharge(b.baseCharge, b.attemptExpandedCharge)
|
||||
if targetCharge > b.chargedSize {
|
||||
if err := b.reservation.growEntry(b.entry, targetCharge); err != nil {
|
||||
if errors.Is(err, ErrInboundRPCQueueFull) {
|
||||
return nil, release, errors.Join(errLayerRPCGZIPCapacity, err)
|
||||
}
|
||||
return nil, release, err
|
||||
}
|
||||
b.chargedSourceBytes = targetSourceBytes
|
||||
b.chargedSize = targetCharge
|
||||
}
|
||||
return data, release, nil
|
||||
}
|
||||
|
|
@ -293,7 +354,9 @@ func (s *Server) prepareInboundLayerRPCBatch(ctx context.Context, c *Conn, plan
|
|||
}
|
||||
expansionBudget := &layerRPCGZIPExpansionBudget{
|
||||
server: s, plan: plan, reservation: reservation,
|
||||
entry: reservationIndex, baseSourceBytes: len(item.body), chargedSourceBytes: len(item.body),
|
||||
entry: reservationIndex,
|
||||
baseCharge: provisionalSpecs[reservationIndex].size,
|
||||
chargedSize: provisionalSpecs[reservationIndex].size,
|
||||
}
|
||||
expansionBudgets[reservationIndex] = expansionBudget
|
||||
options := tlprofile.AdmissionOptions{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue