Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1vgsBe-005tje-02 for pgsql-hackers@arkaria.postgresql.org; Fri, 16 Jan 2026 22:20:58 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.96) (envelope-from ) id 1vgsBc-005OqY-2y for pgsql-hackers@arkaria.postgresql.org; Fri, 16 Jan 2026 22:20:57 +0000 Received: from magus.postgresql.org ([2a02:c0:301:0:ffff::29]) by malur.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1vgsBc-005OqQ-1V for pgsql-hackers@lists.postgresql.org; Fri, 16 Jan 2026 22:20:56 +0000 Received: from mail-lj1-x230.google.com ([2a00:1450:4864:20::230]) by magus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (Exim 4.96) (envelope-from ) id 1vgsBa-000tN5-1S for pgsql-hackers@lists.postgresql.org; Fri, 16 Jan 2026 22:20:56 +0000 Received: by mail-lj1-x230.google.com with SMTP id 38308e7fff4ca-38305f05717so22328561fa.1 for ; Fri, 16 Jan 2026 14:20:54 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1768602053; x=1769206853; darn=lists.postgresql.org; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:from:to:cc:subject:date:message-id:reply-to; bh=ej26in4V5eY1eGW2o7pGqCmMJPoAmtYYJGsEkZBe38U=; b=UvyHGt/kV0nbSmSFiMCMfua/PWcHHQORsZrziVxJpiHYtSPEM8tAKwDpyz2SZ3CILi jYXQVpgMWV5AUjEODgqbOn9DH51xPUIDB+YxB6HDnv6QS1fxRQLyojKneUN41xqO/uZx 4+4aECQNMJgJ4QNOA6ZR0MnJkxUHgJ5zfuSUuabSxdRHo6THQW0qRKd/WYof5iO/HgMJ HKU6RUZUKvQP6/aBxCevuaZfLz6Ct3JiNBosPAe5PQthE8ExPosrvtROrRpelWJoR3to wsaoVk0jMV6BU/mUzz3mziQYwNweBUK8raZzBztZItCV5XwlBnuONA8fc7z08y/olXVX eO2A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1768602053; x=1769206853; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:x-gm-gg:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=ej26in4V5eY1eGW2o7pGqCmMJPoAmtYYJGsEkZBe38U=; b=GobuSUR/vu0YjUAvKRAzRnvFKyrJMGH87XG6XzJy5urKqyFEsUpqXiXOnmtq8OstNk PtjN12tP6odgf7jAX6+yFlI0HoUJUswfnoufO1YVAMzHYTPb5oIbOMgEBEp/IcaWxbXw /YTQ5wAurko3dQw0e+LXDYGqdDzXm3Kat/xDLohkrxRRIdfAAYmc9gxR3TtqQ3Bi6D4m nObHKwwANsRyh6rm/ahVfgSA2xjRyXWNPGwco1C8vMqMRJOBL3ymnyN9z5lO9ZcBZy2L ESJ2cPOuOWH09NXnLtl4WAi/aP4kzRCS7S8RpjOErUz9hrRME2O7JN7v3VCprANgW9gK 4aoA== X-Forwarded-Encrypted: i=1; AJvYcCXuef6xl2hVGZiTj43+Tz0oC44+e3aS89olbMMq8Nl1caufHk+g1L0QcNYe83h8oyYD1NfPNIe4FfmjJwGP@lists.postgresql.org X-Gm-Message-State: AOJu0Yw1Eb7x1TpaNlKKhGI6Ndbgy3W/yyEmcy5P+STmu3+kXg9sxu9j uzLUhH783iSZZYy7vp2mAnPQ7BGXpQTt5iYPrCyXZ2hikRGaVErN4TqnNVMQB2Dw3J2KxYu9gYJ +cXzidvDFIAmcvCR3hJ0KhCssMx7x/Vk= X-Gm-Gg: AY/fxX6wE9gfO5rERrTY9DgK+yujp5NDS9FShot5rey+/RPYLOpUyi6xu8evAilrdcg xtO/RbXHF7Xd3V66QVr1UmTMsnku8vVpooTFoe5/Q6rbac4dGR0DR7OHIKZ0ozc+eoXMgLtYb3H 1eYMoe7LLpsTs7zbwYypkRdkIPoWtsN8ZFCkcYD0xjOII/wUbGU1xPdyg07LtBEEL1dqqqWgPtj aBXiS9KSN7Wmh3+sITTsDdUasdXbMlaehCib4W29r9vSD1jOll5IDAXu4fo6uqw40baxgcc X-Received: by 2002:a05:651c:509:b0:383:1fb6:60a1 with SMTP id 38308e7fff4ca-3838426a273mr15194511fa.20.1768602052525; Fri, 16 Jan 2026 14:20:52 -0800 (PST) MIME-Version: 1.0 References: In-Reply-To: From: Masahiko Sawada Date: Fri, 16 Jan 2026 14:20:14 -0800 X-Gm-Features: AZwV_QjMkhiSxvnaLR-ecJvKsczwhOWkpvbWTRFzE9z9HKOJgJyQ0hFQC_1ggYw Message-ID: Subject: Re: POC: Parallel processing of indexes in autovacuum To: Daniil Davydov <3danissimo@gmail.com> Cc: Sami Imseih , Alexander Korotkov , Matheus Alcantara , Maxim Orlov , Postgres hackers Content-Type: multipart/mixed; boundary="000000000000171670064888c1d3" List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk --000000000000171670064888c1d3 Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable On Fri, Jan 16, 2026 at 6:11=E2=80=AFAM Daniil Davydov <3danissimo@gmail.co= m> wrote: > > Hi, > > On Thu, Jan 15, 2026 at 9:13=E2=80=AFAM Masahiko Sawada wrote: > > > > > > --- > > + /* > > + * Cap the number of free workers by new parameter's value, if need= ed. > > + */ > > + AutoVacuumShmem->av_freeParallelWorkers =3D > > + Min(AutoVacuumShmem->av_freeParallelWorkers, > > + autovacuum_max_parallel_workers); > > + > > + if (autovacuum_max_parallel_workers > prev_max_parallel_workers) > > + { > > + /* > > + * If user wants to increase number of parallel autovacuum work= ers, we > > + * must increase number of free workers. > > + */ > > + AutoVacuumShmem->av_freeParallelWorkers +=3D > > + (autovacuum_max_parallel_workers - prev_max_parallel_worker= s); > > + } > > > > Suppose the previous autovacuum_max_parallel_workers is 5 and there > > are 2 workers are reserved (i.e., there are 3 free parallel workers), > > if the autovacuum_max_parallel_workers changes to 2, the new > > AutoVacuumShmem->av_freeParallelWorkers would be 2 based on the above > > codes, but I believe that the new number of free workers should be 0 > > as there are already 2 workers are running. What do you think? I guess > > we can calculate the new number of free workers by: > > > > Max((autovacuum_max_parallel_workers - prev_max_parallel_workers) + > > AutoVacuumShmem->av_freeParallelWorkers), 0) > > > > If av_max_parallel_workers was changed to 2, then we not only set > freeParallelWorkers to 2 but also set maxParallelWorkers to 2. > Thus, when previously reserved two workers are released, av leader will > encounter this code: > > /* > * If the maximum number of parallel workers was reduced during execution= , > * we must cap available workers number by its new value. > */ > AutoVacuumShmem->av_freeParallelWorkers =3D > Min(AutoVacuumShmem->av_freeParallelWorkers + nworkers, > AutoVacuumShmem->av_maxParallelWorkers); > > I.e. freeParallelWorkers will be left as "2". > > The formula you suggested is also correct, but if you have no objections, > I would prefer not to change the existing logic. It seems more reliable f= or > me when av leader explicitly can consider such a situation. Looking at AutoVacuumReserveParallelWorkers(), it seems that we don't check the av_maxParallelWorkers() there. Is it possible that two more workers would be reserved even while the existing 2 workers are running? /* Provide as many workers as we can. */ *nworkers =3D Min(AutoVacuumShmem->av_freeParallelWorkers, *nworkers); AutoVacuumShmem->av_freeParallelWorkers -=3D *nworkers; Some review comments on v19-0001 patch: + /* Release all the reserved parallel workers for autovacuum */ + if (AmAutoVacuumWorkerProcess() && pvs->pcxt->nworkers_launched > 0= ) + AutoVacuumReleaseParallelWorkers(pvs->pcxt->nworkers_launched); Since we want to release all reserved workers here, I think it's clear if we use AutoVacuumReleaseAllParallelWorkers() and we add Assert(av_nworkers_reserved =3D=3D 0) at the end of AutoVacuumReleaseAllParallelWorkers(). This way, we can ensure that all workers are released and it makes the codes more readable. What do you think? I've attached the patch proposing this change (please find v19-0001_masahiko.patch). --- +#autovacuum_max_parallel_workers =3D 2 # disabled by default and limite= d by + # max_worker_processes It's odd to me that the comment says it's disabled by default while being set to 2. I think we can rewrite the comment to: +#autovacuum_max_parallel_workers =3D 2 # limited by max_worker_processe= s BTW it seems to me that this GUC should be capped by max_parallel_workers instead of max_worker_processes, no? --- + long_desc =3D> 'This parameter is capped by "max_worker_processes" (not by "autovacuum_max_workers"!).', I'm concerned that this kind of description might not be appropriate to the description in long_desc. Looking at long_desc contents of other GUC parameters, we describe the detail of the parameters (e.g., "0 means xxx" or detailed explanation of the effect). Probably we can remove this line. > > > --- > > I've attached a patch proposing some minor changes. > > > > Thanks! I agree with all fixes except a single one: > - * NOTE: We will try to provide as many workers as requested, even if ca= ller > - * will occupy all available workers. > > I think that this is a pretty important point. I'll leave this NOTE in th= e > v19 patch set. Do you mind? No, I agree with that. > > > > > + /* > > + * Number of planned and actually launched parallel workers for all= index > > + * scans, or NULL > > + */ > > + PVWorkersUsage *workers_usage; > > > > I think that LVRelState can have PVWorkersUsage instead of a pointer to= it. > > > > Previously I used the NULL value of this pointer as a flag that we don't = need > to log workers usage. Now I'll add boolean flag for this purpose (IIUC, > "nplanned > 0" condition is not enough to determine whether we should log > workers usage, because VACUUM PARALLEL can be called without VERBOSE). Can't we simply not report the worker usage if nplanned is 0? > > > --- > > + /* > > + * Allocate space for workers usage statistics. Thus, we explic= itly > > + * make clear that such statistics must be accumulated. For now= , this > > + * is used only by autovacuum leader worker, because it must lo= g it in > > + * the end of table processing. > > + */ > > + vacrel->workers_usage =3D AmAutoVacuumWorkerProcess() ? > > + (PVWorkersUsage *) palloc0(sizeof(PVWorkersUsage)) : > > + NULL; > > > > I think we can report the worker statistics even in VACUUM VERBOSE > > logs. Currently VACUUM VERBOSE reports the worker usage just during > > index vacuuming but it would make sense to report the overall > > statistics in vacuum logs. It would help make VACUUM VERBOSE logs and > > autovacuum logs consistent. > > > > Agree. > > > But we don't need to report the worker usage if we didn't use the > > parallel vacuum (i.e., if npanned =3D=3D 0). > > > > As I wrote above - we don't need to log workers usage if the VERBOSE opti= on > is not specified (even if nplanned > 0). Am I missing something? No. My point is that even when the VERBOSE option is specified, we can skip reporting the worker usage if the parallel vacuum is not even planned. That is, I think we can do like: if (vacrel->workers_usage.nplanned > 0) appendStringInfo(&buf, _("parallel index vacuum/cleanup: %d workers were planned and %d workers were launched in total\n"), vacrel->workers_usage.nplanned, vacrel->workers_usage.nlaunched); > > > --- > > + /* Remember these values, if we asked to. */ > > + if (wusage !=3D NULL) > > + { > > + wusage->nlaunched +=3D pvs->pcxt->nworkers_launched; > > + wusage->nplanned +=3D nworkers; > > + } > > > > This code runs after the attempt to reserve parallel workers. > > Consequently, if we fail to reserve any workers due to > > autovacuum_max_parallel_workers, we report the status as if parallel > > vacuum wasn't planned at all. I think knowing the number of workers > > that were planned but not reserved would provide valuable insight for > > users tuning autovacuum_max_parallel_workers. > > > > 100% agree. Thank you for updating the patch. I think that we need the explanation of what nlaunched and nplanned actually mean in the PVWorkersUsage definition: +typedef struct PVWorkersUsage +{ + int nlaunched; + int nplanned; +} PVWorkersUsage; I'm concerned that readers might be confused that nplanned is not the number of parallel workers we actually planned to launch. Or it might make sense to track these three values: planned, reserved, and launched. For example, suppose max_worker_processes =3D 10 and autovacuum_max_parallel_workers =3D 5, if two autovacuum workers try to reserve 3 workers each, one worker can reserve and launch 3 and another worker can reserve and launch 2. The autovacuum logs would be "3 planned and 3 launched" and "3 planned and 2 launched". Users can deal with the shortage of parallel workers by increasing autovacuum_max_parallel_workers. On the other hand, if some bgworkers are being used by other components (.e.g, parallel queries, logical replication etc.) and there are only 2 free bgworkers, the autovacuum worker can reserve 3 but can launch only 2, and other worker can reserve 2 but cannot launch any workers. The autovacuum logs would be "3 planned and 2 launched" and "3 planned and 0 launched". Here increasing autovacuum_max_parallel_workers resolves the shortage of parallel workers, but users would have to increase max_worker_processes instead. If we can report the worker usage like "3 planned, 3 reserved, and 2 launched" and "3 planned, 2 reserved, and 0 launched", users would realize the need to increase max_worker_processes. Of course, the "xxx reserved" information would not be necessary for VACUUM VERBOSE logs. > > > > > +typedef enum AVLeaderFaulureType > > +{ > > + FAIL_NONE, > > + FAIL_ERROR, > > + FAIL_FATAL, > > +} AVLeaderFaulureType; > > > > I'm concerned that it is somewhat overwrapped with what injection > > points does as we can set 'error' to injection_points_attach(). For > > the FATAL error, we can terminate the autovacuum worker by using > > pg_terminate_backend() that keeps waiting due to > > injection_point_attach() with action=3D'wait'. > > > > Oh, I didn't know about the possibility of testing FATAL errors with > pg_terminate_backend. After reading your letter I found this pattern > in signal_autovacuum.pl. This is beautiful. > Thank you, I'll rework these tests. +1 > > > --- > > It would be great if we could test the av_freeParallelWorkers > > adjustment when max_parallel_maintenance_workers changes. > > > > You mean "when autovacuum_max_parallel_workers changes"? > I'll add a test for it. Yes, thanks! > > > --- > > + if (!AmAutoVacuumWorkerProcess()) > > + { > > + /* > > + * If we are autovacuum parallel worker, check whether cost-bas= ed > > + * parameters had changed in leader worker. > > + * If so, vacuum_cost_delay and vacuum_cost_limit will be set t= o the > > + * values which leader worker is operating on. > > + * > > + * Do it before checking VacuumCostActive, because its value mi= ght be > > + * changed after leader's parameters consumption. > > + */ > > + parallel_vacuum_fix_cost_based_params(); > > + } > > > > We need to add checks to prevent the normal backend running the VACUUM > > command from calling parallel_vacuum_fix_cost_based_params(). > > > > We already have such check inside the "fix_cost_based" function : > /* Check whether we are running parallel autovacuum */ > if (pv_shared_cost_params =3D=3D NULL) > return false; > > We also have this comment: > * If we are autovacuum parallel worker, check whether cost-based > * parameters had changed in leader worker. > > As an alternative, I'll add comment explicitly saying that process will > immediately return if it not parallel autovacuum participant. Why don't we add IsInParallelMode() or IsParallelWorker() check before calling parallel_vacuum_update_shared_delay_params()? Some review comments on v19-0003 patch: +bool +parallel_vacuum_update_shared_delay_params(void) +{ + /* Check whether we are running parallel autovacuum */ + if (pv_shared_cost_params =3D=3D NULL) + return false; + + Assert(IsParallelWorker() && !AmAutoVacuumWorkerProcess()); These codes are a bit odd to me in two points: 1. A process can never be both a parallel worker and an autovacuum worker. 2. If pv_shared_cost_parame =3D=3D NULL, even autovacuum workers and non-parallel workers can call this function, but it seems to be unexpected function call given the subsequent assertion. If we want to have an assertion to ensure that a function is called only by processes we expect or allow, I think we should add an assertion to the beginning of function. How about rewriting these parts to: Assert(IsParallelWorker()); /* Check whether we are running parallel autovacuum */ if (pv_shared_cost_params =3D=3D NULL) return false; --- + * Note, that this function has no effect if we are non-autovacuum + * parallel worker. + */ I don't think this kind of comment should be noted here since if we change the parallel_vacuum_update_shared_delay_params() behavior in the future, such comments would get easily out-of-sync. > > > + Assert(IsParallelWorker() && !AmAutoVacuumWorkerProcess()); > > + > > + SpinLockAcquire(&pv_shared_cost_params->spinlock); > > + > > + vacuum_cost_delay =3D pv_shared_cost_params->cost_delay; > > + vacuum_cost_limit =3D pv_shared_cost_params->cost_limit; > > + > > + SpinLockRelease(&pv_shared_cost_params->spinlock); > > > > IIUC autovacuum parallel workers seems to update their > > vacuum_cost_{delay|limit} every vacuum_delay_point(), which seems not > > good. Can we somehow avoid unnecessary updates? > > More precisely, parallel worker *reads* leader's parameters every delay_p= oint. > Obviously, this does not mean that the parameters will necessarily be upd= ated. > > But I don't see anything wrong with this logic. We just every time get th= e most > relevant parameters from the leader. Of course we can introduce some > signaling mechanism, but it will have the same effect as in the current c= ode. Although the parameter propagation itself is working correctly, the current implementation seems suboptimal performance-wise. Acquiring an additional spinlock and updating the local variables for every block seems too costly to me. IIUC we would end up incurring these costs even when vacuum delays are disabled. I think we need to find a better way. For example, we can have a generation of these parameters. That is, the leader increments the generation (stored in PVSharedCostParams) whenever updating them after reloading the configuration file, and workers maintain its generation of the parameters currently used. If the worker's generation < the global generation, it updates its parameters along with its generation. I think we can implement the generation using pg_atomic_u32, making the check for parameter updates lock-free. There might be better ideas, though. I'll review the patches for regression tests and the documentation. Regards, -- Masahiko Sawada Amazon Web Services: https://aws.amazon.com --000000000000171670064888c1d3 Content-Type: application/octet-stream; name="v19-0001_masahiko.patch" Content-Disposition: attachment; filename="v19-0001_masahiko.patch" Content-Transfer-Encoding: base64 Content-ID: X-Attachment-Id: f_mkhfypyw0 ZGlmZiAtLWdpdCBhL3NyYy9iYWNrZW5kL2NvbW1hbmRzL3ZhY3V1bXBhcmFsbGVsLmMgYi9zcmMv YmFja2VuZC9jb21tYW5kcy92YWN1dW1wYXJhbGxlbC5jCmluZGV4IGNiNDJkNGU1NzJmLi4xZTM1 YjgyYWVhZiAxMDA2NDQKLS0tIGEvc3JjL2JhY2tlbmQvY29tbWFuZHMvdmFjdXVtcGFyYWxsZWwu YworKysgYi9zcmMvYmFja2VuZC9jb21tYW5kcy92YWN1dW1wYXJhbGxlbC5jCkBAIC03NjQsNyAr NzY0LDcgQEAgcGFyYWxsZWxfdmFjdXVtX3Byb2Nlc3NfYWxsX2luZGV4ZXMoUGFyYWxsZWxWYWN1 dW1TdGF0ZSAqcHZzLCBpbnQgbnVtX2luZGV4X3NjYW4KIAogCQkvKiBSZWxlYXNlIGFsbCB0aGUg cmVzZXJ2ZWQgcGFyYWxsZWwgd29ya2VycyBmb3IgYXV0b3ZhY3V1bSAqLwogCQlpZiAoQW1BdXRv VmFjdXVtV29ya2VyUHJvY2VzcygpICYmIHB2cy0+cGN4dC0+bndvcmtlcnNfbGF1bmNoZWQgPiAw KQotCQkJQXV0b1ZhY3V1bVJlbGVhc2VQYXJhbGxlbFdvcmtlcnMocHZzLT5wY3h0LT5ud29ya2Vy c19sYXVuY2hlZCk7CisJCQlBdXRvVmFjdXVtUmVsZWFzZUFsbFBhcmFsbGVsV29ya2VycygpOwog CX0KIAogCS8qCmRpZmYgLS1naXQgYS9zcmMvYmFja2VuZC9wb3N0bWFzdGVyL2F1dG92YWN1dW0u YyBiL3NyYy9iYWNrZW5kL3Bvc3RtYXN0ZXIvYXV0b3ZhY3V1bS5jCmluZGV4IDA5N2IxZGQ1NWNm Li5iZGQ2NjM2MTBmNSAxMDA2NDQKLS0tIGEvc3JjL2JhY2tlbmQvcG9zdG1hc3Rlci9hdXRvdmFj dXVtLmMKKysrIGIvc3JjL2JhY2tlbmQvcG9zdG1hc3Rlci9hdXRvdmFjdXVtLmMKQEAgLTM3Myw3 ICszNzMsNiBAQCBzdGF0aWMgdm9pZCBhdmxfc2lndXNyMl9oYW5kbGVyKFNJR05BTF9BUkdTKTsK IHN0YXRpYyBib29sIGF2X3dvcmtlcl9hdmFpbGFibGUodm9pZCk7CiBzdGF0aWMgdm9pZCBjaGVj a19hdl93b3JrZXJfZ3Vjcyh2b2lkKTsKIHN0YXRpYyB2b2lkIGFkanVzdF9mcmVlX3BhcmFsbGVs X3dvcmtlcnMoaW50IHByZXZfbWF4X3BhcmFsbGVsX3dvcmtlcnMpOwotc3RhdGljIHZvaWQgQXV0 b1ZhY3V1bVJlbGVhc2VBbGxQYXJhbGxlbFdvcmtlcnModm9pZCk7CiAKIAogCkBAIC0zMzkxLDYg KzMzOTAsOSBAQCBBdXRvVmFjdXVtUmVxdWVzdFdvcmsoQXV0b1ZhY3V1bVdvcmtJdGVtVHlwZSB0 eXBlLCBPaWQgcmVsYXRpb25JZCwKICAqCiAgKiBud29ya2VycyBpcyBhbiBpbi9vdXQgcGFyYW1l dGVyOyB0aGUgcmVxdWVzdGVkIG51bWJlciBvZiBwYXJhbGxlbCB3b3JrZXJzCiAgKiB0byByZXNl cnZlIGJ5IHRoZSBjYWxsZXIsIGFuZCBzZXQgdG8gdGhlIGFjdHVhbCBudW1iZXIgb2YgcmVzZXJ2 ZWQgd29ya2Vycy4KKyAqCisgKiBUaGUgY2FsbGVyIG11c3QgY2FsbCBBdXRvVmFjdXVtUmVsZWFz ZVBhcmFsbGVsV29ya2VycygpIHRvIHJlbGVhc2UgdGhlCisgKiByZXNlcnZlZCB3b3JrZXJzLgog ICovCiB2b2lkCiBBdXRvVmFjdXVtUmVzZXJ2ZVBhcmFsbGVsV29ya2VycyhpbnQgKm53b3JrZXJz KQpAQCAtMzQxNCwxMSArMzQxNiwxMiBAQCBBdXRvVmFjdXVtUmVzZXJ2ZVBhcmFsbGVsV29ya2Vy cyhpbnQgKm53b3JrZXJzKQogfQogCiAvKgotICogTGVhZGVyIGF1dG92YWN1dW0gcHJvY2VzcyBt dXN0IGNhbGwgdGhpcyBmdW5jdGlvbiBpbiBvcmRlciB0byB1cGRhdGUgZ2xvYmFsCi0gKiBhdXRv dmFjdXVtIHN0YXRlLCBzbyBvdGhlciBsZWFkZXJzIHdpbGwgYmUgYWJsZSB0byB1c2UgdGhlc2Ug cGFyYWxsZWwKLSAqIHdvcmtlcnMuCisgKiBSZWxlYXNlcyB0aGUgcmVzZXJ2ZWQgcGFyYWxsZWwg d29ya2VycyBmb3IgYXV0b3ZhY3V1bS4KICAqCi0gKiAnbndvcmtlcnMnIC0gaG93IG1hbnkgd29y a2VycyBjYWxsZXIgd2FudHMgdG8gcmVsZWFzZS4KKyAqIFRoaXMgZnVuY3Rpb24gc2hvdWxkIGJl IHVzZWQgdG8gcmVsZWFzZSB0aGUgcGFyYWxsZWwgd29ya2VycyB0aGF0IGFuCisgKiBhdXRvdmFj dXVtIHdvcmtlciByZXNlcnZlZCBieSBBdXRvVmFjdXVtUmVzZXJ2ZVBhcmFsbGVsV29ya2Vycygp LiBud29ya2VycworICogaXMgdGhlIG51bWJlciBvZiB3b3JrZXJzIHRvIHJlbGVhc2UsIHdoaWNo IG11c3Qgbm90IGJlIGdyZWF0ZXIgdGhhbiB0aGUKKyAqIG51bWJlciBvZiB3b3JrZXJzIGN1cnJl bnRseSByZXNlcnZlZCwgYXZfbndvcmtlcnNfcmVzZXJ2ZWQuCiAgKi8KIHZvaWQKIEF1dG9WYWN1 dW1SZWxlYXNlUGFyYWxsZWxXb3JrZXJzKGludCBud29ya2VycykKQEAgLTM0MjYsNiArMzQyOSw5 IEBAIEF1dG9WYWN1dW1SZWxlYXNlUGFyYWxsZWxXb3JrZXJzKGludCBud29ya2VycykKIAkvKiBP bmx5IGxlYWRlciB3b3JrZXIgY2FuIGNhbGwgdGhpcyBmdW5jdGlvbi4gKi8KIAlBc3NlcnQoQW1B dXRvVmFjdXVtV29ya2VyUHJvY2VzcygpICYmICFJc1BhcmFsbGVsV29ya2VyKCkpOwogCisJLyog Q2Fubm90IHJlbGVhc2UgbW9yZSB3b3JrZXJzIHRoYW4gcmVzZXJ2ZWQgKi8KKwlBc3NlcnQobndv cmtlcnMgPD0gYXZfbndvcmtlcnNfcmVzZXJ2ZWQpOworCiAJTFdMb2NrQWNxdWlyZShBdXRvdmFj dXVtTG9jaywgTFdfRVhDTFVTSVZFKTsKIAogCS8qCkBAIC0zNDQzLDggKzM0NDksOCBAQCBBdXRv VmFjdXVtUmVsZWFzZVBhcmFsbGVsV29ya2VycyhpbnQgbndvcmtlcnMpCiB9CiAKIC8qCi0gKiBT YW1lIGFzIGFib3ZlLCBidXQgcmVsZWFzZSAqYWxsKiBwYXJhbGxlbCB3b3JrZXJzLCB0aGF0IHdl cmUgcmVzZXJ2ZWQgYnkKLSAqIGN1cnJlbnQgbGVhZGVyIGF1dG92YWN1dW0gcHJvY2Vzcy4KKyAq IFNpbWlsYXIgdG8gQXV0b1ZhY3V1bVJlbGVhc2VQYXJhbGxlbFdvcmtlcnMoKSwgYnV0IHRoaXMg ZnVuY3Rpb24gcmVsZWFzZXMKKyAqIGFsbCB0aGUgcGFyYWxsZWwgd29ya2VycyB0aGF0IHRoaXMg YXV0b3ZhY3V1bSB3b3JrZXIgcmVzZXJ2ZWQuCiAgKi8KIHN0YXRpYyB2b2lkCiBBdXRvVmFjdXVt UmVsZWFzZUFsbFBhcmFsbGVsV29ya2Vycyh2b2lkKQpAQCAtMzQ1NCw2ICszNDYwLDggQEAgQXV0 b1ZhY3V1bVJlbGVhc2VBbGxQYXJhbGxlbFdvcmtlcnModm9pZCkKIAogCWlmIChhdl9ud29ya2Vy c19yZXNlcnZlZCA+IDApCiAJCUF1dG9WYWN1dW1SZWxlYXNlUGFyYWxsZWxXb3JrZXJzKGF2X253 b3JrZXJzX3Jlc2VydmVkKTsKKworCUFzc2VydChhdl9ud29ya2Vyc19yZXNlcnZlZCA9PSAwKTsK IH0KIAogLyoKZGlmZiAtLWdpdCBhL3NyYy9pbmNsdWRlL3Bvc3RtYXN0ZXIvYXV0b3ZhY3V1bS5o IGIvc3JjL2luY2x1ZGUvcG9zdG1hc3Rlci9hdXRvdmFjdXVtLmgKaW5kZXggM2Y1YjU5YTE1YmQu LmYzNzgzYWZiNTFiIDEwMDY0NAotLS0gYS9zcmMvaW5jbHVkZS9wb3N0bWFzdGVyL2F1dG92YWN1 dW0uaAorKysgYi9zcmMvaW5jbHVkZS9wb3N0bWFzdGVyL2F1dG92YWN1dW0uaApAQCAtNjUsNiAr NjUsNyBAQCBleHRlcm4gYm9vbCBBdXRvVmFjdXVtUmVxdWVzdFdvcmsoQXV0b1ZhY3V1bVdvcmtJ dGVtVHlwZSB0eXBlLAogLyogcGFyYWxsZWwgYXV0b3ZhY3V1bSBzdHVmZiAqLwogZXh0ZXJuIHZv aWQJQXV0b1ZhY3V1bVJlc2VydmVQYXJhbGxlbFdvcmtlcnMoaW50ICpud29ya2Vycyk7CiBleHRl cm4gdm9pZCBBdXRvVmFjdXVtUmVsZWFzZVBhcmFsbGVsV29ya2VycyhpbnQgbndvcmtlcnMpOwor ZXh0ZXJuIHZvaWQgQXV0b1ZhY3V1bVJlbGVhc2VBbGxQYXJhbGxlbFdvcmtlcnModm9pZCk7CiAK IC8qIHNoYXJlZCBtZW1vcnkgc3R1ZmYgKi8KIGV4dGVybiBTaXplIEF1dG9WYWN1dW1TaG1lbVNp emUodm9pZCk7Cg== --000000000000171670064888c1d3--