Skip to content
Projeler
Gruplar
Parçacıklar
Yardım
Yükleniyor...
Oturum aç / Kaydol
Gezinmeyi değiştir
C
cpython
Proje
Proje
Ayrıntılar
Etkinlik
Cycle Analytics
Depo (repository)
Depo (repository)
Dosyalar
Kayıtlar (commit)
Dallar (branch)
Etiketler
Katkıda bulunanlar
Grafik
Karşılaştır
Grafikler
Konular (issue)
0
Konular (issue)
0
Liste
Pano
Etiketler
Kilometre Taşları
Birleştirme (merge) Talepleri
0
Birleştirme (merge) Talepleri
0
CI / CD
CI / CD
İş akışları (pipeline)
İşler
Zamanlamalar
Grafikler
Paketler
Paketler
Wiki
Wiki
Parçacıklar
Parçacıklar
Üyeler
Üyeler
Collapse sidebar
Close sidebar
Etkinlik
Grafik
Grafikler
Yeni bir konu (issue) oluştur
İşler
Kayıtlar (commit)
Konu (issue) Panoları
Kenar çubuğunu aç
Batuhan Osman TASKAYA
cpython
Commits
1211c9a9
Unverified
Kaydet (Commit)
1211c9a9
authored
Ock 20, 2018
tarafından
Serhiy Storchaka
Kaydeden (comit)
GitHub
Ock 20, 2018
Dosyalara gözat
Seçenekler
Dosyalara Gözat
İndir
Eposta Yamaları
Sade Fark
bpo-32503: Avoid creating too small frames in pickles. (#5127)
üst
bd5c7d23
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
62 additions
and
51 deletions
+62
-51
pickle.py
Lib/pickle.py
+7
-5
pickletester.py
Lib/test/pickletester.py
+45
-37
2018-01-07-09-22-26.bpo-32503.ViMxpD.rst
...S.d/next/Library/2018-01-07-09-22-26.bpo-32503.ViMxpD.rst
+1
-0
_pickle.c
Modules/_pickle.c
+9
-9
No files found.
Lib/pickle.py
Dosyayı görüntüle @
1211c9a9
...
@@ -183,6 +183,7 @@ __all__.extend([x for x in dir() if re.match("[A-Z][A-Z0-9_]+$", x)])
...
@@ -183,6 +183,7 @@ __all__.extend([x for x in dir() if re.match("[A-Z][A-Z0-9_]+$", x)])
class
_Framer
:
class
_Framer
:
_FRAME_SIZE_MIN
=
4
_FRAME_SIZE_TARGET
=
64
*
1024
_FRAME_SIZE_TARGET
=
64
*
1024
def
__init__
(
self
,
file_write
):
def
__init__
(
self
,
file_write
):
...
@@ -203,11 +204,12 @@ class _Framer:
...
@@ -203,11 +204,12 @@ class _Framer:
if
f
.
tell
()
>=
self
.
_FRAME_SIZE_TARGET
or
force
:
if
f
.
tell
()
>=
self
.
_FRAME_SIZE_TARGET
or
force
:
data
=
f
.
getbuffer
()
data
=
f
.
getbuffer
()
write
=
self
.
file_write
write
=
self
.
file_write
# Issue a single call to the write method of the underlying
if
len
(
data
)
>=
self
.
_FRAME_SIZE_MIN
:
# file object for the frame opcode with the size of the
# Issue a single call to the write method of the underlying
# frame. The concatenation is expected to be less expensive
# file object for the frame opcode with the size of the
# than issuing an additional call to write.
# frame. The concatenation is expected to be less expensive
write
(
FRAME
+
pack
(
"<Q"
,
len
(
data
)))
# than issuing an additional call to write.
write
(
FRAME
+
pack
(
"<Q"
,
len
(
data
)))
# Issue a separate call to write to append the frame
# Issue a separate call to write to append the frame
# contents without concatenation to the above to avoid a
# contents without concatenation to the above to avoid a
...
...
Lib/test/pickletester.py
Dosyayı görüntüle @
1211c9a9
...
@@ -2037,6 +2037,7 @@ class AbstractPickleTests(unittest.TestCase):
...
@@ -2037,6 +2037,7 @@ class AbstractPickleTests(unittest.TestCase):
# Exercise framing (proto >= 4) for significant workloads
# Exercise framing (proto >= 4) for significant workloads
FRAME_SIZE_MIN
=
4
FRAME_SIZE_TARGET
=
64
*
1024
FRAME_SIZE_TARGET
=
64
*
1024
def
check_frame_opcodes
(
self
,
pickled
):
def
check_frame_opcodes
(
self
,
pickled
):
...
@@ -2047,36 +2048,43 @@ class AbstractPickleTests(unittest.TestCase):
...
@@ -2047,36 +2048,43 @@ class AbstractPickleTests(unittest.TestCase):
framed by default and are therefore considered a frame by themselves in
framed by default and are therefore considered a frame by themselves in
the following consistency check.
the following consistency check.
"""
"""
last_arg
=
last_pos
=
last_frame_opcode_size
=
None
frame_end
=
frameless_start
=
None
frameless_opcode_sizes
=
{
frameless_opcodes
=
{
'BINBYTES'
,
'BINUNICODE'
,
'BINBYTES8'
,
'BINUNICODE8'
}
'BINBYTES'
:
5
,
'BINUNICODE'
:
5
,
'BINBYTES8'
:
9
,
'BINUNICODE8'
:
9
,
}
for
op
,
arg
,
pos
in
pickletools
.
genops
(
pickled
):
for
op
,
arg
,
pos
in
pickletools
.
genops
(
pickled
):
if
op
.
name
in
frameless_opcode_sizes
:
if
frame_end
is
not
None
:
if
len
(
arg
)
>
self
.
FRAME_SIZE_TARGET
:
self
.
assertLessEqual
(
pos
,
frame_end
)
frame_opcode_size
=
frameless_opcode_sizes
[
op
.
name
]
if
pos
==
frame_end
:
arg
=
len
(
arg
)
frame_end
=
None
else
:
continue
if
frame_end
is
not
None
:
# framed
elif
op
.
name
==
'FRAME'
:
self
.
assertNotEqual
(
op
.
name
,
'FRAME'
)
frame_opcode_size
=
9
if
op
.
name
in
frameless_opcodes
:
else
:
# Only short bytes and str objects should be written
continue
# in a frame
self
.
assertLessEqual
(
len
(
arg
),
self
.
FRAME_SIZE_TARGET
)
if
last_pos
is
not
None
:
# The previous frame's size should be equal to the number
else
:
# not framed
# of bytes up to the current frame.
if
(
op
.
name
==
'FRAME'
or
frame_size
=
pos
-
last_pos
-
last_frame_opcode_size
(
op
.
name
in
frameless_opcodes
and
self
.
assertEqual
(
frame_size
,
last_arg
)
len
(
arg
)
>
self
.
FRAME_SIZE_TARGET
)):
last_arg
,
last_pos
=
arg
,
pos
# Frame or large bytes or str object
last_frame_opcode_size
=
frame_opcode_size
if
frameless_start
is
not
None
:
# The last frame's size should be equal to the number of bytes up
# Only short data should be written outside of a frame
# to the pickle's end.
self
.
assertLess
(
pos
-
frameless_start
,
frame_size
=
len
(
pickled
)
-
last_pos
-
last_frame_opcode_size
self
.
FRAME_SIZE_MIN
)
self
.
assertEqual
(
frame_size
,
last_arg
)
frameless_start
=
None
elif
frameless_start
is
None
and
op
.
name
!=
'PROTO'
:
frameless_start
=
pos
if
op
.
name
==
'FRAME'
:
self
.
assertGreaterEqual
(
arg
,
self
.
FRAME_SIZE_MIN
)
frame_end
=
pos
+
9
+
arg
pos
=
len
(
pickled
)
if
frame_end
is
not
None
:
self
.
assertEqual
(
frame_end
,
pos
)
elif
frameless_start
is
not
None
:
self
.
assertLess
(
pos
-
frameless_start
,
self
.
FRAME_SIZE_MIN
)
def
test_framing_many_objects
(
self
):
def
test_framing_many_objects
(
self
):
obj
=
list
(
range
(
10
**
5
))
obj
=
list
(
range
(
10
**
5
))
...
@@ -2095,7 +2103,8 @@ class AbstractPickleTests(unittest.TestCase):
...
@@ -2095,7 +2103,8 @@ class AbstractPickleTests(unittest.TestCase):
def
test_framing_large_objects
(
self
):
def
test_framing_large_objects
(
self
):
N
=
1024
*
1024
N
=
1024
*
1024
obj
=
[
b
'x'
*
N
,
b
'y'
*
N
,
'z'
*
N
]
small_items
=
[[
i
]
for
i
in
range
(
10
)]
obj
=
[
b
'x'
*
N
,
*
small_items
,
b
'y'
*
N
,
'z'
*
N
]
for
proto
in
range
(
4
,
pickle
.
HIGHEST_PROTOCOL
+
1
):
for
proto
in
range
(
4
,
pickle
.
HIGHEST_PROTOCOL
+
1
):
for
fast
in
[
False
,
True
]:
for
fast
in
[
False
,
True
]:
with
self
.
subTest
(
proto
=
proto
,
fast
=
fast
):
with
self
.
subTest
(
proto
=
proto
,
fast
=
fast
):
...
@@ -2119,12 +2128,9 @@ class AbstractPickleTests(unittest.TestCase):
...
@@ -2119,12 +2128,9 @@ class AbstractPickleTests(unittest.TestCase):
# Perform full equality check if the lengths match.
# Perform full equality check if the lengths match.
self
.
assertEqual
(
obj
,
unpickled
)
self
.
assertEqual
(
obj
,
unpickled
)
n_frames
=
count_opcode
(
pickle
.
FRAME
,
pickled
)
n_frames
=
count_opcode
(
pickle
.
FRAME
,
pickled
)
if
not
fast
:
# A single frame for small objects between
# One frame per memoize for each large object.
# first two large objects.
self
.
assertGreaterEqual
(
n_frames
,
len
(
obj
))
self
.
assertEqual
(
n_frames
,
1
)
else
:
# One frame at the beginning and one at the end.
self
.
assertGreaterEqual
(
n_frames
,
2
)
self
.
check_frame_opcodes
(
pickled
)
self
.
check_frame_opcodes
(
pickled
)
def
test_optional_frames
(
self
):
def
test_optional_frames
(
self
):
...
@@ -2152,7 +2158,9 @@ class AbstractPickleTests(unittest.TestCase):
...
@@ -2152,7 +2158,9 @@ class AbstractPickleTests(unittest.TestCase):
frame_size
=
self
.
FRAME_SIZE_TARGET
frame_size
=
self
.
FRAME_SIZE_TARGET
num_frames
=
20
num_frames
=
20
obj
=
[
bytes
([
i
])
*
frame_size
for
i
in
range
(
num_frames
)]
# Large byte objects (dict values) intermitted with small objects
# (dict keys)
obj
=
{
i
:
bytes
([
i
])
*
frame_size
for
i
in
range
(
num_frames
)}
for
proto
in
range
(
4
,
pickle
.
HIGHEST_PROTOCOL
+
1
):
for
proto
in
range
(
4
,
pickle
.
HIGHEST_PROTOCOL
+
1
):
pickled
=
self
.
dumps
(
obj
,
proto
)
pickled
=
self
.
dumps
(
obj
,
proto
)
...
...
Misc/NEWS.d/next/Library/2018-01-07-09-22-26.bpo-32503.ViMxpD.rst
0 → 100644
Dosyayı görüntüle @
1211c9a9
Pickling with protocol 4 no longer creates too small frames.
Modules/_pickle.c
Dosyayı görüntüle @
1211c9a9
...
@@ -119,8 +119,8 @@ enum {
...
@@ -119,8 +119,8 @@ enum {
/* Prefetch size when unpickling (disabled on unpeekable streams) */
/* Prefetch size when unpickling (disabled on unpeekable streams) */
PREFETCH = 8192 * 16,
PREFETCH = 8192 * 16,
FRAME_SIZE_MIN = 4,
FRAME_SIZE_TARGET = 64 * 1024,
FRAME_SIZE_TARGET = 64 * 1024,
FRAME_HEADER_SIZE = 9
FRAME_HEADER_SIZE = 9
};
};
...
@@ -949,13 +949,6 @@ _write_size64(char *out, size_t value)
...
@@ -949,13 +949,6 @@ _write_size64(char *out, size_t value)
}
}
}
}
static
void
_Pickler_WriteFrameHeader
(
PicklerObject
*
self
,
char
*
qdata
,
size_t
frame_len
)
{
qdata
[
0
]
=
FRAME
;
_write_size64
(
qdata
+
1
,
frame_len
);
}
static int
static int
_Pickler_CommitFrame(PicklerObject *self)
_Pickler_CommitFrame(PicklerObject *self)
{
{
...
@@ -966,7 +959,14 @@ _Pickler_CommitFrame(PicklerObject *self)
...
@@ -966,7 +959,14 @@ _Pickler_CommitFrame(PicklerObject *self)
return 0;
return 0;
frame_len = self->output_len - self->frame_start - FRAME_HEADER_SIZE;
frame_len = self->output_len - self->frame_start - FRAME_HEADER_SIZE;
qdata = PyBytes_AS_STRING(self->output_buffer) + self->frame_start;
qdata = PyBytes_AS_STRING(self->output_buffer) + self->frame_start;
_Pickler_WriteFrameHeader
(
self
,
qdata
,
frame_len
);
if (frame_len >= FRAME_SIZE_MIN) {
qdata[0] = FRAME;
_write_size64(qdata + 1, frame_len);
}
else {
memmove(qdata, qdata + FRAME_HEADER_SIZE, frame_len);
self->output_len -= FRAME_HEADER_SIZE;
}
self->frame_start = -1;
self->frame_start = -1;
return 0;
return 0;
}
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment