Skip to content

Commit 42a70d1

Browse files
committed
tupleslots!
we completely ditch the old HeapTuple code, that's way too icky to work with (not safe) what we may consider at some point is something like a "tupleslot lite" which only carries a heaptuple + bufferpin by-value, but for now we don't need that
1 parent aa2a408 commit 42a70d1

9 files changed

Lines changed: 219 additions & 126 deletions

File tree

build.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ fn main() {
2626
writeln!(f, "const CACHEID_TYPEOID: i32 = {};", pgbuild::cacheid_typeoid()).unwrap();
2727

2828
writeln!(f, "const RELATT_OFFSET: usize = {};", pgbuild::relatt_offset()).unwrap();
29+
writeln!(f, "const RS_CBUF_OFFSET: usize = {};", pgbuild::rs_cbuf_offset()).unwrap();
30+
writeln!(f, "const XS_CBUF_OFFSET: usize = {};", pgbuild::xs_cbuf_offset()).unwrap();
2931

3032

3133
assert_ne!(pgbuild::float4_byval(), 0);

pgbuild/src/gluedefs.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#include <stdint.h>
22
#include <postgres.h>
33
#include <access/skey.h>
4+
#include <access/relscan.h>
45
#include <utils/syscache.h>
56
#include <utils/rel.h>
67
#include <setjmp.h>
@@ -18,3 +19,5 @@ uint32_t len_sigjmpbuf() { return sizeof(sigjmp_buf); }
1819
uint32_t cacheid_typeoid() { return TYPEOID; }
1920

2021
uint32_t relatt_offset() { return offsetof(RelationData, rd_att); }
22+
uint32_t rs_cbuf_offset() { return offsetof(HeapScanDescData, rs_cbuf); }
23+
uint32_t xs_cbuf_offset() { return offsetof(IndexScanDescData, xs_cbuf); }

pgbuild/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,6 @@ extern "C" {
1010

1111
pub fn cacheid_typeoid() -> u32;
1212
pub fn relatt_offset() -> u32;
13+
pub fn rs_cbuf_offset() -> u32;
14+
pub fn xs_cbuf_offset() -> u32;
1315
}

src/heap.rs

Lines changed: 42 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -2,48 +2,67 @@ use std::os::raw::c_void;
22
use std::marker::PhantomData;
33
use std::ptr;
44

5+
use alloc::MemoryContext;
56
use types::Oid;
67
use error;
7-
use Datum;
8-
use relation::{Relation, RawTupleDesc, GetTransactionSnapshot};
8+
use relation::{Relation, GetTransactionSnapshot};
99
use tupledesc::{TupleDesc, RefTupleDesc};
10+
use tupleslot::{EmptyTupleSlot, TupleSlot};
1011

11-
type HeapScanDesc = *mut c_void;
12+
#[repr(C)]
13+
struct HeapScanDescData {
14+
_pad: [u8; ::RS_CBUF_OFFSET],
15+
rs_cbuf: i32,
16+
}
17+
type HeapScanDesc = *mut HeapScanDescData;
1218

19+
type HeapTupleData = c_void;
1320
extern "C" {
1421
fn heap_open(relation: Oid, lockmode: i32) -> *const Relation;
1522
fn relation_close(relation: *const Relation, lockmode: i32);
1623

1724
fn heap_beginscan(relation: *const Relation, snapshot: *mut c_void, nkeys: i32, scankeys: *mut u8) -> HeapScanDesc;
1825
//fn heap_rescan(scan: HeapScanDesc, scankeys: *mut u8);
19-
fn heap_getnext(scan: HeapScanDesc, direction: i32) -> *const HeapTupleData<'static>;
26+
fn heap_getnext(scan: HeapScanDesc, direction: i32) -> *const HeapTupleData;
2027
fn heap_endscan(scan: HeapScanDesc);
2128

22-
fn heap_deform_tuple(tuple: *const HeapTupleData, desc: *const RawTupleDesc, values: *mut Datum, isnull: *mut bool);
29+
//fn heap_deform_tuple(tuple: *const HeapTupleData, desc: *const RawTupleDesc, values: *mut Datum, isnull: *mut bool);
2330
}
2431

32+
33+
2534
// FIXME private member
2635
pub struct Heap(pub(crate) *const Relation);
27-
pub struct HeapScan<'a> {
36+
pub struct RawHeapScan<'a> {
2837
ptr: HeapScanDesc,
29-
tupledesc: *const RawTupleDesc,
3038
marker: PhantomData<&'a Heap>,
3139
}
3240

41+
pub struct HeapScan<'alloc, 'h> {
42+
raw: RawHeapScan<'h>,
43+
slot: EmptyTupleSlot<'alloc, RefTupleDesc<'h>>,
44+
}
45+
3346
impl Heap {
3447
pub fn open(oid: Oid) -> Heap {
3548
unsafe {
3649
error::convert_postgres_error(|| Heap(heap_open(oid, 1)) )
3750
}
3851
}
3952

40-
pub fn scan(&self) -> HeapScan {
53+
pub fn scan<'alloc, 'h>(&'h self, alloc: &'alloc MemoryContext<'alloc>) -> HeapScan<'alloc, 'h> {
54+
HeapScan {
55+
raw: self.scan_raw(),
56+
slot: EmptyTupleSlot::create(self.tuple_desc(), alloc),
57+
}
58+
}
59+
60+
pub fn scan_raw<'a>(&'a self) -> RawHeapScan<'a> {
4161
error::convert_postgres_error(|| {
4262
unsafe {
4363
let snap = GetTransactionSnapshot();
44-
HeapScan {
64+
RawHeapScan {
4565
ptr: heap_beginscan(self.0, snap, 0, ptr::null_mut()),
46-
tupledesc: (*self.0).td,
4766
marker: PhantomData,
4867
}
4968
}
@@ -57,77 +76,36 @@ impl Heap {
5776
}
5877
}
5978

60-
61-
62-
// TODO: verify in build that C compiler is capable of aligning
63-
#[repr(C)]
64-
#[derive(Clone, Copy)]
65-
struct ItemPointerData {
66-
foo: [u8; 6]
67-
}
68-
69-
70-
#[repr(C)]
71-
struct HeapTupleHeader {
72-
pad: [u8; 22],
73-
//pad: [u8; RELATT_OFFSET],
74-
t_hoff: u8,
75-
// tail ...
76-
}
77-
78-
pub struct HeapTuple<'a> {
79-
pub(crate) data: HeapTupleData<'a>,
80-
pub(crate) tupledesc: *const RawTupleDesc,
81-
}
82-
83-
// FIXME: make private
84-
#[repr(C)]
85-
#[derive(Clone, Copy)]
86-
pub(crate) struct HeapTupleData<'a> {
87-
t_len: u32,
88-
t_self: ItemPointerData,
89-
t_tableOid: Oid,
90-
t_data: &'a HeapTupleHeader,
91-
}
92-
93-
94-
impl<'a> HeapTuple<'a> {
95-
pub fn deform(&self) -> Vec<Option<Datum<'a>>> {
79+
impl<'alloc, 'h> HeapScan<'alloc, 'h> {
80+
pub fn next<'a>(&'a mut self) -> Option<TupleSlot<'alloc, 'a, 'h, RefTupleDesc<'h>>> {
9681
unsafe {
97-
error::convert_postgres_error(|| {
98-
let natts = (*self.tupledesc).natts as usize;
99-
let mut vals: Vec<Datum> = Vec::with_capacity(natts);
100-
let mut flags: Vec<bool> = Vec::with_capacity(natts);
101-
vals.set_len(natts);
102-
flags.set_len(natts);
103-
104-
heap_deform_tuple(&self.data, self.tupledesc, vals.as_mut_ptr(), flags.as_mut_ptr());
105-
106-
vals.into_iter().zip(flags).map(|(v, f)| if f { None } else { Some(v) }).collect()
107-
})
82+
match self.raw.next() {
83+
None => None,
84+
Some(tuple) => {
85+
let buffer = (*self.raw.ptr).rs_cbuf;
86+
Some(self.slot.store_tuple(tuple, buffer))
87+
}
88+
}
10889
}
10990
}
11091
}
11192

112-
impl<'a> Iterator for HeapScan<'a> {
113-
type Item = HeapTuple<'a>;
93+
impl<'a> Iterator for RawHeapScan<'a> {
94+
type Item = *const HeapTupleData;
11495

11596
fn next(&mut self) -> Option<Self::Item> {
11697
unsafe {
11798
let tuple = error::convert_postgres_error(|| heap_getnext(self.ptr, 1));
11899
if tuple.is_null() {
119100
None
120101
} else {
121-
Some(HeapTuple {
122-
data: *tuple,
123-
tupledesc: self.tupledesc,
124-
})
102+
Some(tuple)
125103
}
126104
}
127105
}
128106
}
129107

130-
impl<'a> Drop for HeapScan<'a> {
108+
impl<'a> Drop for RawHeapScan<'a> {
131109
fn drop(&mut self) {
132110
unsafe {
133111
error::convert_postgres_error_dtor(|| heap_endscan(self.ptr))
@@ -142,31 +120,3 @@ impl Drop for Heap {
142120
}
143121
}
144122
}
145-
/*
146-
pub fn do_index_scan(rel: Oid, idx: Oid) -> i32 {
147-
let mut counter = 0;
148-
unsafe {
149-
let heap = heap_open(rel, 1);
150-
let index = index_open(idx, 1);
151-
152-
let btint4cmp = 184;
153-
let mut keybuf = [0u8; ::LEN_SCANKEYDATA];
154-
ScanKeyInit(keybuf.as_mut_ptr(), 1, 3, btint4cmp, 4);
155-
156-
let snap = GetTransactionSnapshot();
157-
assert!(!snap.is_null());
158-
let scan = index_beginscan(heap, index, snap, 1, 0);
159-
index_rescan(scan, keybuf.as_mut_ptr(), 1, ptr::null_mut(), 0);
160-
loop {
161-
let thing = index_getnext(scan, 1);
162-
if thing.is_null() { break; }
163-
counter += 1;
164-
}
165-
index_endscan(scan);
166-
167-
index_close(index, 1);
168-
relation_close(heap, 1);
169-
}
170-
counter
171-
}
172-
*/

src/index.rs

Lines changed: 50 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,35 @@
11
use std::os::raw::c_void;
22
use std::marker::PhantomData;
33
use std::{ptr, mem};
4+
45
use types::Oid;
56
use error;
6-
use heap::{Heap, HeapTuple, HeapTupleData};
7+
use heap::Heap;
78
use relation::{Relation, GetTransactionSnapshot};
9+
use alloc::MemoryContext;
10+
use tupledesc::RefTupleDesc;
11+
use tupleslot::{EmptyTupleSlot, TupleSlot};
812

9-
type IndexScanDesc = *mut c_void;
13+
#[repr(C)]
14+
struct IndexScanDescData {
15+
_pad: [u8; ::XS_CBUF_OFFSET],
16+
xs_cbuf: i32,
17+
}
18+
type IndexScanDesc = *mut IndexScanDescData;
1019
extern "C" {
1120
fn index_open(relation: Oid, lockmode: i32 /* set to 1 */) -> *const Relation;
1221
fn index_close(relation: *const Relation, lockmode: i32);
1322
fn index_beginscan(heap: *const Relation, index: *const Relation, snapshot: *mut c_void /* null */, nkeys: i32, norderbys: i32) -> IndexScanDesc;
1423
// afaik orderbys are broken and unused
1524
fn index_rescan(scan: IndexScanDesc, scankeys: *const ScanKey, nkeys: i32, orderbys: *mut u8, norderbys: i32);
16-
fn index_getnext(scan: IndexScanDesc, direction: i32) -> *mut HeapTupleData<'static>; // returns HeapTuple
25+
fn index_getnext(scan: IndexScanDesc, direction: i32) -> *mut c_void;
1726
//fn index_getnext_tid(scan: IndexScanDesc, direction: i32) -> *mut c_void; // returns ItemPointer
1827
fn index_endscan(scan: IndexScanDesc);
1928

2029
fn ScanKeyInit(entry: *mut ScanKey, attr_num: u16, strat_num: u16, regproc: u32, arg: usize);
2130
}
2231

32+
2333
#[repr(C)]
2434
pub struct ScanKey {
2535
_pad: [u8; ::LEN_SCANKEYDATA],
@@ -45,36 +55,52 @@ impl ScanKey {
4555
// FIXME: validate index structure (postgres does not guard against invalid scankeys,
4656
// most importantly column id needs to be valid or things break horribly)
4757

48-
pub struct IndexScan<'a> {
58+
pub struct RawIndexScan<'a> {
4959
ptr: IndexScanDesc,
5060
marker: PhantomData<&'a Index>,
51-
heap: &'a Heap,
5261
}
53-
impl<'a> Iterator for IndexScan<'a> {
54-
type Item = HeapTuple<'a>;
62+
impl<'a> Iterator for RawIndexScan<'a> {
63+
type Item = *const c_void;
5564

5665
fn next(&mut self) -> Option<Self::Item> {
5766
unsafe {
5867
let tuple = error::convert_postgres_error(|| index_getnext(self.ptr, 1));
5968
if tuple.is_null() {
6069
None
6170
} else {
62-
Some(HeapTuple {
63-
data: *tuple,
64-
tupledesc: (*self.heap.0).td,
65-
})
71+
Some(tuple)
6672
}
6773
}
6874
}
6975
}
70-
impl<'a> Drop for IndexScan<'a> {
76+
impl<'a> Drop for RawIndexScan<'a> {
7177
fn drop(&mut self) {
7278
unsafe {
7379
error::convert_postgres_error_dtor(|| index_endscan(self.ptr))
7480
}
7581
}
7682
}
7783

84+
85+
pub struct IndexScan<'alloc, 'a> {
86+
raw: RawIndexScan<'a>,
87+
slot: EmptyTupleSlot<'alloc, RefTupleDesc<'a>>,
88+
}
89+
90+
impl<'alloc, 'a> IndexScan<'alloc, 'a> {
91+
pub fn next<'b>(&'b mut self) -> Option<TupleSlot<'alloc, 'b, 'a, RefTupleDesc<'a>>> {
92+
unsafe {
93+
match self.raw.next() {
94+
None => None,
95+
Some(tuple) => {
96+
let buffer = (*self.raw.ptr).xs_cbuf;
97+
Some(self.slot.store_tuple(tuple, buffer))
98+
}
99+
}
100+
}
101+
}
102+
}
103+
78104
pub struct Index(*const Relation);
79105
impl Index {
80106
pub fn open(oid: Oid) -> Index {
@@ -83,7 +109,17 @@ impl Index {
83109
}
84110
}
85111

86-
pub fn scan<'a>(&'a self, heap: &'a Heap, scankeys: &'a [ScanKey]) -> IndexScan<'a> {
112+
pub fn scan<'alloc, 'a>(&'a self,
113+
heap: &'a Heap,
114+
scankeys: &'a [ScanKey],
115+
alloc: &'alloc MemoryContext<'alloc>) -> IndexScan<'alloc, 'a> {
116+
IndexScan {
117+
raw: self.scan_raw(heap, scankeys),
118+
slot: EmptyTupleSlot::create(heap.tuple_desc(), alloc),
119+
}
120+
}
121+
122+
pub fn scan_raw<'a>(&'a self, heap: &'a Heap, scankeys: &'a [ScanKey]) -> RawIndexScan<'a> {
87123
assert!(scankeys.len() <= 1);
88124

89125
unsafe {
@@ -94,10 +130,9 @@ impl Index {
94130
let intlen = scankeys.len() as i32;
95131
let scan = index_beginscan(heap.0, self.0, snap, intlen, 0);
96132
index_rescan(scan, scankeys.as_ptr(), intlen, ptr::null_mut(), 0);
97-
IndexScan {
133+
RawIndexScan {
98134
ptr: scan,
99135
marker: PhantomData,
100-
heap,
101136
}
102137
})
103138
}

0 commit comments

Comments
 (0)