Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit7e0cce0

Browse files
committed
Remove unnecessary overhead in backend's large-object operations.
Do read/write permissions checks at most once per large object descriptor,not once per lo_read or lo_write call as before. The repeated tests werequite useless in the read case since the snapshot-based tests wereguaranteed to produce the same answer every time. In the write case,the extra tests could in principle detect revocation of write privilegesafter a series of writes has started --- but there's a race condition thereanyway, since we'd check privileges before performing and certainly beforecommitting the write. So there's no real advantage to checking everysingle time, and we might as well redefine it as "only check the firsttime".On the same reasoning, remove the LargeObjectExists checks in inv_writeand inv_truncate. We already checked existence when the descriptor wasopened, and checking again doesn't provide any real increment of safetythat would justify the cost.
1 parent2d8c81a commit7e0cce0

File tree

3 files changed

+88
-89
lines changed

3 files changed

+88
-89
lines changed

‎src/backend/libpq/be-fsstubs.c

Lines changed: 74 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -157,24 +157,32 @@ int
157157
lo_read(intfd,char*buf,intlen)
158158
{
159159
intstatus;
160+
LargeObjectDesc*lobj;
160161

161162
if (fd<0||fd >=cookies_size||cookies[fd]==NULL)
162163
ereport(ERROR,
163164
(errcode(ERRCODE_UNDEFINED_OBJECT),
164165
errmsg("invalid large-object descriptor: %d",fd)));
166+
lobj=cookies[fd];
165167

166-
/* Permission checks */
167-
if (!lo_compat_privileges&&
168-
pg_largeobject_aclcheck_snapshot(cookies[fd]->id,
169-
GetUserId(),
170-
ACL_SELECT,
171-
cookies[fd]->snapshot)!=ACLCHECK_OK)
172-
ereport(ERROR,
173-
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
174-
errmsg("permission denied for large object %u",
175-
cookies[fd]->id)));
168+
/* We don't bother to check IFS_RDLOCK, since it's always set */
169+
170+
/* Permission checks --- first time through only */
171+
if ((lobj->flags&IFS_RD_PERM_OK)==0)
172+
{
173+
if (!lo_compat_privileges&&
174+
pg_largeobject_aclcheck_snapshot(lobj->id,
175+
GetUserId(),
176+
ACL_SELECT,
177+
lobj->snapshot)!=ACLCHECK_OK)
178+
ereport(ERROR,
179+
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
180+
errmsg("permission denied for large object %u",
181+
lobj->id)));
182+
lobj->flags |=IFS_RD_PERM_OK;
183+
}
176184

177-
status=inv_read(cookies[fd],buf,len);
185+
status=inv_read(lobj,buf,len);
178186

179187
returnstatus;
180188
}
@@ -183,30 +191,36 @@ int
183191
lo_write(intfd,constchar*buf,intlen)
184192
{
185193
intstatus;
194+
LargeObjectDesc*lobj;
186195

187196
if (fd<0||fd >=cookies_size||cookies[fd]==NULL)
188197
ereport(ERROR,
189198
(errcode(ERRCODE_UNDEFINED_OBJECT),
190199
errmsg("invalid large-object descriptor: %d",fd)));
200+
lobj=cookies[fd];
191201

192-
if ((cookies[fd]->flags&IFS_WRLOCK)==0)
202+
if ((lobj->flags&IFS_WRLOCK)==0)
193203
ereport(ERROR,
194204
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
195205
errmsg("large object descriptor %d was not opened for writing",
196206
fd)));
197207

198-
/* Permission checks */
199-
if (!lo_compat_privileges&&
200-
pg_largeobject_aclcheck_snapshot(cookies[fd]->id,
201-
GetUserId(),
202-
ACL_UPDATE,
203-
cookies[fd]->snapshot)!=ACLCHECK_OK)
204-
ereport(ERROR,
205-
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
206-
errmsg("permission denied for large object %u",
207-
cookies[fd]->id)));
208+
/* Permission checks --- first time through only */
209+
if ((lobj->flags&IFS_WR_PERM_OK)==0)
210+
{
211+
if (!lo_compat_privileges&&
212+
pg_largeobject_aclcheck_snapshot(lobj->id,
213+
GetUserId(),
214+
ACL_UPDATE,
215+
lobj->snapshot)!=ACLCHECK_OK)
216+
ereport(ERROR,
217+
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
218+
errmsg("permission denied for large object %u",
219+
lobj->id)));
220+
lobj->flags |=IFS_WR_PERM_OK;
221+
}
208222

209-
status=inv_write(cookies[fd],buf,len);
223+
status=inv_write(lobj,buf,len);
210224

211225
returnstatus;
212226
}
@@ -230,8 +244,8 @@ lo_lseek(PG_FUNCTION_ARGS)
230244
if (status!= (int32)status)
231245
ereport(ERROR,
232246
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
233-
errmsg("lo_lseek result out of range for large-object descriptor %d",
234-
fd)));
247+
errmsg("lo_lseek result out of range for large-object descriptor %d",
248+
fd)));
235249

236250
PG_RETURN_INT32((int32)status);
237251
}
@@ -303,8 +317,8 @@ lo_tell(PG_FUNCTION_ARGS)
303317
if (offset!= (int32)offset)
304318
ereport(ERROR,
305319
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
306-
errmsg("lo_tell result out of range for large-object descriptor %d",
307-
fd)));
320+
errmsg("lo_tell result out of range for large-object descriptor %d",
321+
fd)));
308322

309323
PG_RETURN_INT32((int32)offset);
310324
}
@@ -558,30 +572,48 @@ lo_export(PG_FUNCTION_ARGS)
558572
* lo_truncate -
559573
* truncate a large object to a specified length
560574
*/
561-
Datum
562-
lo_truncate(PG_FUNCTION_ARGS)
575+
staticvoid
576+
lo_truncate_internal(int32fd,int64len)
563577
{
564-
int32fd=PG_GETARG_INT32(0);
565-
int32len=PG_GETARG_INT32(1);
578+
LargeObjectDesc*lobj;
566579

567580
if (fd<0||fd >=cookies_size||cookies[fd]==NULL)
568581
ereport(ERROR,
569582
(errcode(ERRCODE_UNDEFINED_OBJECT),
570583
errmsg("invalid large-object descriptor: %d",fd)));
584+
lobj=cookies[fd];
571585

572-
/* Permission checks */
573-
if (!lo_compat_privileges&&
574-
pg_largeobject_aclcheck_snapshot(cookies[fd]->id,
575-
GetUserId(),
576-
ACL_UPDATE,
577-
cookies[fd]->snapshot)!=ACLCHECK_OK)
586+
if ((lobj->flags&IFS_WRLOCK)==0)
578587
ereport(ERROR,
579-
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
580-
errmsg("permission denied for large object %u",
581-
cookies[fd]->id)));
588+
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
589+
errmsg("large object descriptor %d was not opened for writing",
590+
fd)));
591+
592+
/* Permission checks --- first time through only */
593+
if ((lobj->flags&IFS_WR_PERM_OK)==0)
594+
{
595+
if (!lo_compat_privileges&&
596+
pg_largeobject_aclcheck_snapshot(lobj->id,
597+
GetUserId(),
598+
ACL_UPDATE,
599+
lobj->snapshot)!=ACLCHECK_OK)
600+
ereport(ERROR,
601+
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
602+
errmsg("permission denied for large object %u",
603+
lobj->id)));
604+
lobj->flags |=IFS_WR_PERM_OK;
605+
}
582606

583-
inv_truncate(cookies[fd],len);
607+
inv_truncate(lobj,len);
608+
}
584609

610+
Datum
611+
lo_truncate(PG_FUNCTION_ARGS)
612+
{
613+
int32fd=PG_GETARG_INT32(0);
614+
int32len=PG_GETARG_INT32(1);
615+
616+
lo_truncate_internal(fd,len);
585617
PG_RETURN_INT32(0);
586618
}
587619

@@ -591,24 +623,7 @@ lo_truncate64(PG_FUNCTION_ARGS)
591623
int32fd=PG_GETARG_INT32(0);
592624
int64len=PG_GETARG_INT64(1);
593625

594-
if (fd<0||fd >=cookies_size||cookies[fd]==NULL)
595-
ereport(ERROR,
596-
(errcode(ERRCODE_UNDEFINED_OBJECT),
597-
errmsg("invalid large-object descriptor: %d",fd)));
598-
599-
/* Permission checks */
600-
if (!lo_compat_privileges&&
601-
pg_largeobject_aclcheck_snapshot(cookies[fd]->id,
602-
GetUserId(),
603-
ACL_UPDATE,
604-
cookies[fd]->snapshot)!=ACLCHECK_OK)
605-
ereport(ERROR,
606-
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
607-
errmsg("permission denied for large object %u",
608-
cookies[fd]->id)));
609-
610-
inv_truncate(cookies[fd],len);
611-
626+
lo_truncate_internal(fd,len);
612627
PG_RETURN_INT32(0);
613628
}
614629

‎src/backend/storage/large_object/inv_api.c

Lines changed: 4 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -420,8 +420,8 @@ inv_seek(LargeObjectDesc *obj_desc, int64 offset, int whence)
420420
if (newoffset<0||newoffset>MAX_LARGE_OBJECT_SIZE)
421421
ereport(ERROR,
422422
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
423-
errmsg_internal("invalid large object seek target: "INT64_FORMAT,
424-
newoffset)));
423+
errmsg_internal("invalid large object seek target: "INT64_FORMAT,
424+
newoffset)));
425425

426426
obj_desc->offset=newoffset;
427427
returnnewoffset;
@@ -562,18 +562,7 @@ inv_write(LargeObjectDesc *obj_desc, const char *buf, int nbytes)
562562
Assert(buf!=NULL);
563563

564564
/* enforce writability because snapshot is probably wrong otherwise */
565-
if ((obj_desc->flags&IFS_WRLOCK)==0)
566-
ereport(ERROR,
567-
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
568-
errmsg("large object %u was not opened for writing",
569-
obj_desc->id)));
570-
571-
/* check existence of the target largeobject */
572-
if (!LargeObjectExists(obj_desc->id))
573-
ereport(ERROR,
574-
(errcode(ERRCODE_UNDEFINED_OBJECT),
575-
errmsg("large object %u was already dropped",
576-
obj_desc->id)));
565+
Assert(obj_desc->flags&IFS_WRLOCK);
577566

578567
if (nbytes <=0)
579568
return0;
@@ -767,18 +756,7 @@ inv_truncate(LargeObjectDesc *obj_desc, int64 len)
767756
Assert(PointerIsValid(obj_desc));
768757

769758
/* enforce writability because snapshot is probably wrong otherwise */
770-
if ((obj_desc->flags&IFS_WRLOCK)==0)
771-
ereport(ERROR,
772-
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
773-
errmsg("large object %u was not opened for writing",
774-
obj_desc->id)));
775-
776-
/* check existence of the target largeobject */
777-
if (!LargeObjectExists(obj_desc->id))
778-
ereport(ERROR,
779-
(errcode(ERRCODE_UNDEFINED_OBJECT),
780-
errmsg("large object %u was already dropped",
781-
obj_desc->id)));
759+
Assert(obj_desc->flags&IFS_WRLOCK);
782760

783761
/*
784762
* use errmsg_internal here because we don't want to expose INT64_FORMAT

‎src/include/storage/large_object.h

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@
2727
* offset is the current seek offset within the LO
2828
* flags contains some flag bits
2929
*
30+
* NOTE: in current usage, flag bit IFS_RDLOCK is *always* set, and we don't
31+
* bother to test for it. Permission checks are made at first read or write
32+
* attempt, not during inv_open(), so we have other bits to remember that.
33+
*
3034
* NOTE: before 7.1, we also had to store references to the separate table
3135
* and index of a specific large object. Now they all live in pg_largeobject
3236
* and are accessed via a common relation descriptor.
@@ -38,11 +42,13 @@ typedef struct LargeObjectDesc
3842
Snapshotsnapshot;/* snapshot to use */
3943
SubTransactionIdsubid;/* owning subtransaction ID */
4044
uint64offset;/* current seek pointer */
41-
intflags;/*locking info, etc */
45+
intflags;/*see flag bits below */
4246

43-
/* flag bits: */
44-
#defineIFS_RDLOCK(1 << 0)
45-
#defineIFS_WRLOCK(1 << 1)
47+
/* bits in flags: */
48+
#defineIFS_RDLOCK(1 << 0)/* LO was opened for reading */
49+
#defineIFS_WRLOCK(1 << 1)/* LO was opened for writing */
50+
#defineIFS_RD_PERM_OK(1 << 2)/* read permission has been verified */
51+
#defineIFS_WR_PERM_OK(1 << 3)/* write permission has been verified */
4652

4753
}LargeObjectDesc;
4854

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp