PreparePartitionDownscaleHandler prepares the live-store's partition downscaling. The partition owned by the live-store will switch to INACTIVE state (read-only). Following methods are supported: - GET Returns timestamp when partition was switched to INACTIVE state, or 0, if partition is not in IN
(w http.ResponseWriter, r *http.Request)
| 31 | // - DELETE |
| 32 | // Sets partition back from INACTIVE to ACTIVE state. |
| 33 | func (s *LiveStore) PreparePartitionDownscaleHandler(w http.ResponseWriter, r *http.Request) { |
| 34 | logger := log.With(s.logger, "partition", s.ingestPartitionID) |
| 35 | |
| 36 | // Don't allow callers to change the shutdown configuration while we're in the middle |
| 37 | // of starting or shutting down. |
| 38 | if s.State() != services.Running { |
| 39 | w.WriteHeader(http.StatusServiceUnavailable) |
| 40 | return |
| 41 | } |
| 42 | |
| 43 | if s.ingestPartitionLifecycler == nil { |
| 44 | w.WriteHeader(http.StatusInternalServerError) |
| 45 | return |
| 46 | } |
| 47 | |
| 48 | switch r.Method { |
| 49 | case http.MethodPost: |
| 50 | // It's not allowed to prepare the downscale while in PENDING state. Why? Because if the downscale |
| 51 | // will be later cancelled, we don't know if it was requested in PENDING or ACTIVE state, so we |
| 52 | // don't know to which state reverting back. Given a partition is expected to stay in PENDING state |
| 53 | // for a short period, we simply don't allow this case. |
| 54 | state, _, err := s.ingestPartitionLifecycler.GetPartitionState(r.Context()) |
| 55 | if err != nil { |
| 56 | level.Error(logger).Log("msg", "cannot downscale: failed to check partition state in the ring", "err", err) |
| 57 | w.WriteHeader(http.StatusInternalServerError) |
| 58 | return |
| 59 | } |
| 60 | |
| 61 | if state == ring.PartitionPending { |
| 62 | level.Warn(logger).Log("msg", "received a request to prepare partition for shutdown, but the request can't be satisfied because the partition is in PENDING state") |
| 63 | w.WriteHeader(http.StatusConflict) |
| 64 | return |
| 65 | } |
| 66 | if state == ring.PartitionInactive { |
| 67 | level.Debug(logger).Log("msg", "partition is already set to INACTIVE state") |
| 68 | break |
| 69 | } |
| 70 | |
| 71 | if err := s.ingestPartitionLifecycler.ChangePartitionState(r.Context(), ring.PartitionInactive); err != nil { |
| 72 | level.Error(logger).Log("msg", "failed to change partition state to inactive", "err", err) |
| 73 | w.WriteHeader(http.StatusInternalServerError) |
| 74 | return |
| 75 | } |
| 76 | |
| 77 | level.Info(logger).Log("msg", "partition prepared for downscaling") |
| 78 | |
| 79 | case http.MethodDelete: |
| 80 | state, _, err := s.ingestPartitionLifecycler.GetPartitionState(r.Context()) |
| 81 | if err != nil { |
| 82 | level.Error(logger).Log("msg", "cannot cancel downscaling: failed to check partition state in the ring", "err", err) |
| 83 | w.WriteHeader(http.StatusInternalServerError) |
| 84 | return |
| 85 | } |
| 86 | |
| 87 | // If partition is inactive, make it active. We ignore other states Active and especially Pending. |
| 88 | if state == ring.PartitionInactive { |
| 89 | // We don't switch it back to PENDING state if there are not enough owners because we want to guarantee consistency |
| 90 | // in the read path. If the partition is within the lookback period we need to guarantee that partition will be queried. |
nothing calls this directly
no test coverage detected