From 926201c69aec135ee5ee2a066c8d7e7ed8f0c7d1 Mon Sep 17 00:00:00 2001 From: Lev Date: Tue, 7 Nov 2023 11:46:45 -0800 Subject: [PATCH 01/15] htab --- pgrx/src/lib.rs | 1 + pgrx/src/shmem_hash.rs | 67 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+) create mode 100644 pgrx/src/shmem_hash.rs diff --git a/pgrx/src/lib.rs b/pgrx/src/lib.rs index c57d90c22..8ae00ec77 100644 --- a/pgrx/src/lib.rs +++ b/pgrx/src/lib.rs @@ -65,6 +65,7 @@ pub mod pg_catalog; pub mod pgbox; pub mod rel; pub mod shmem; +pub mod shmem_hash; pub mod spi; #[cfg(feature = "cshim")] pub mod spinlock; diff --git a/pgrx/src/shmem_hash.rs b/pgrx/src/shmem_hash.rs new file mode 100644 index 000000000..5824fbf7e --- /dev/null +++ b/pgrx/src/shmem_hash.rs @@ -0,0 +1,67 @@ +use crate::lwlock::*; +use crate::{pg_sys, PgAtomic}; +use crate::shmem::PgSharedMemoryInitialization; +use std::hash::Hash; +use uuid::Uuid; + +#[derive(Debug, Eq, PartialEq)] +#[non_exhaustive] +pub enum Error { + HashTableFull, +} + +pub struct PgHTab { + htab: *mut pg_sys::HTAB, + size: i64, +} + +impl PgHTab { + pub fn new(size: i64) -> PgHTab { + PgHTab:: { + htab: std::ptr::null(), + size, + } + } + + pub fn insert(&mut self, key: &K, value: &V) -> Result, Error> { + let void_ptr: *const core::ffi::c_void = &key as *const _ as *const core::ffi::c_void; + let mut found = false; + + // Delete entry if exists + let entry = unsafe { + pg_sys::hash_search( + &mut self.htab, + void_ptr, + pg_sys::HASH_REMOVE, + &mut found, + ) + }; + drop(key); + drop(value); + } +} + +impl PgSharedMemoryInitialization for PgHTab { + fn pg_init(&'static self) {} + fn shmem_init(&'static self) { + let key_size = std::mem::size_of::(); + let value_size = std::mem::size_of::(); + + let mut hash_ctl = pg_sys::HASHCTL::default(); + hash_ctl.keysize = key_size; + hash_ctl.entrysize = value_size; + + let shm_name = alloc::ffi::CString::new(Uuid::new_v4().to_string()) + .expect("CString::new() failed"); + + self.htab = unsafe { + pg_sys::ShmemInitHash( + shm_name.into_raw(), + self.size, + self.size, + &mut hash_ctl, + pg_sys::HASH_ELEM | pg_sys::HASH_BLOBS, + ) + }; + } +} From afb25ab9910bd5fafea44a564dbcaee7ae63e8ba Mon Sep 17 00:00:00 2001 From: Lev Kokotov Date: Tue, 7 Nov 2023 14:37:37 -0800 Subject: [PATCH 02/15] hmmm --- pgrx-examples/shmem/src/lib.rs | 8 +++ pgrx/src/shmem_hash.rs | 106 ++++++++++++++++++--------------- 2 files changed, 66 insertions(+), 48 deletions(-) diff --git a/pgrx-examples/shmem/src/lib.rs b/pgrx-examples/shmem/src/lib.rs index e34d015a5..48775a548 100644 --- a/pgrx-examples/shmem/src/lib.rs +++ b/pgrx-examples/shmem/src/lib.rs @@ -11,6 +11,7 @@ use pgrx::atomics::*; use pgrx::lwlock::PgLwLock; use pgrx::prelude::*; use pgrx::shmem::*; +use pgrx::shmem_hash::*; use pgrx::{pg_shmem_init, warning}; use serde::*; use std::iter::Iterator; @@ -39,6 +40,7 @@ static HASH: PgLwLock> = PgLwLock::new(); static STRUCT: PgLwLock = PgLwLock::new(); static PRIMITIVE: PgLwLock = PgLwLock::new(); static ATOMIC: PgAtomic = PgAtomic::new(); +static HASH_TABLE: PgHashMap = PgHashMap::new(25); #[pg_guard] pub extern "C" fn _PG_init() { @@ -48,6 +50,7 @@ pub extern "C" fn _PG_init() { pg_shmem_init!(STRUCT); pg_shmem_init!(PRIMITIVE); pg_shmem_init!(ATOMIC); + pg_shmem_init!(HASH_TABLE); } #[pg_extern] @@ -60,6 +63,11 @@ fn vec_count() -> i32 { VEC.share().len() as i32 } +#[pg_extern] +fn hash_table_insert(key: i64, value: i64) { + HASH_TABLE.insert(&key, &value); +} + #[pg_extern] fn vec_drain() -> SetOfIterator<'static, Pgtest> { let mut vec = VEC.exclusive(); diff --git a/pgrx/src/shmem_hash.rs b/pgrx/src/shmem_hash.rs index 5824fbf7e..e3e3ba08f 100644 --- a/pgrx/src/shmem_hash.rs +++ b/pgrx/src/shmem_hash.rs @@ -1,7 +1,7 @@ use crate::lwlock::*; -use crate::{pg_sys, PgAtomic}; use crate::shmem::PgSharedMemoryInitialization; -use std::hash::Hash; +use crate::PgSharedMem; +use crate::{pg_sys, PGRXSharedMemory}; use uuid::Uuid; #[derive(Debug, Eq, PartialEq)] @@ -10,58 +10,68 @@ pub enum Error { HashTableFull, } -pub struct PgHTab { - htab: *mut pg_sys::HTAB, - size: i64, +#[derive(Copy, Clone)] +pub struct PgHashMapInner { + htab: *mut pg_sys::HTAB, } -impl PgHTab { - pub fn new(size: i64) -> PgHTab { - PgHTab:: { - htab: std::ptr::null(), - size, - } - } +unsafe impl PGRXSharedMemory for PgHashMapInner {} +unsafe impl Send for PgHashMapInner {} +unsafe impl Sync for PgHashMapInner {} - pub fn insert(&mut self, key: &K, value: &V) -> Result, Error> { - let void_ptr: *const core::ffi::c_void = &key as *const _ as *const core::ffi::c_void; - let mut found = false; +impl Default for PgHashMapInner { + fn default() -> Self { + Self { htab: std::ptr::null_mut() } + } +} + +pub struct PgHashMap { + htab: PgLwLock, + size: u64, +} + +impl PgHashMap { + pub const fn new(size: u64) -> PgHashMap { + PgHashMap { htab: PgLwLock::new(), size } + } - // Delete entry if exists - let entry = unsafe { - pg_sys::hash_search( - &mut self.htab, - void_ptr, - pg_sys::HASH_REMOVE, - &mut found, - ) - }; - drop(key); - drop(value); - } + pub fn insert(&self, key: &i64, _value: &i64) { + let htab = self.htab.exclusive(); + let void_ptr: *const core::ffi::c_void = key as *const _ as *const core::ffi::c_void; + let mut found = false; + + let _entry = unsafe { + pg_sys::hash_search(htab.htab, void_ptr, pg_sys::HASHACTION_HASH_ENTER_NULL, &mut found) + }; + } } -impl PgSharedMemoryInitialization for PgHTab { - fn pg_init(&'static self) {} - fn shmem_init(&'static self) { - let key_size = std::mem::size_of::(); - let value_size = std::mem::size_of::(); - - let mut hash_ctl = pg_sys::HASHCTL::default(); - hash_ctl.keysize = key_size; - hash_ctl.entrysize = value_size; +impl PgSharedMemoryInitialization for PgHashMap { + fn pg_init(&'static self) { + PgSharedMem::pg_init_locked(&self.htab); + } + + fn shmem_init(&'static self) { + PgSharedMem::shmem_init_locked(&self.htab); + let mut htab = self.htab.exclusive(); + + let mut hash_ctl = pg_sys::HASHCTL::default(); + hash_ctl.keysize = std::mem::size_of::(); + hash_ctl.entrysize = std::mem::size_of::(); + + let shm_name = + alloc::ffi::CString::new(Uuid::new_v4().to_string()).expect("CString::new() failed"); - let shm_name = alloc::ffi::CString::new(Uuid::new_v4().to_string()) - .expect("CString::new() failed"); + let htab_ptr = unsafe { + pg_sys::ShmemInitHash( + shm_name.into_raw(), + self.size.try_into().unwrap(), + self.size.try_into().unwrap(), + &mut hash_ctl, + (pg_sys::HASH_ELEM | pg_sys::HASH_BLOBS).try_into().unwrap(), + ) + }; - self.htab = unsafe { - pg_sys::ShmemInitHash( - shm_name.into_raw(), - self.size, - self.size, - &mut hash_ctl, - pg_sys::HASH_ELEM | pg_sys::HASH_BLOBS, - ) - }; - } + htab.htab = htab_ptr; + } } From 31ddf43a25d8c4377e58de7d20a25dcfb6f5e4a8 Mon Sep 17 00:00:00 2001 From: Lev Kokotov Date: Wed, 8 Nov 2023 08:47:50 -0800 Subject: [PATCH 03/15] wah --- pgrx-examples/shmem/src/lib.rs | 2 +- pgrx/src/shmem_hash.rs | 44 +++++++++++++++++++++++++++++----- 2 files changed, 39 insertions(+), 7 deletions(-) diff --git a/pgrx-examples/shmem/src/lib.rs b/pgrx-examples/shmem/src/lib.rs index 48775a548..e0d399bfe 100644 --- a/pgrx-examples/shmem/src/lib.rs +++ b/pgrx-examples/shmem/src/lib.rs @@ -65,7 +65,7 @@ fn vec_count() -> i32 { #[pg_extern] fn hash_table_insert(key: i64, value: i64) { - HASH_TABLE.insert(&key, &value); + HASH_TABLE.insert(key, value); } #[pg_extern] diff --git a/pgrx/src/shmem_hash.rs b/pgrx/src/shmem_hash.rs index e3e3ba08f..e01b1efd9 100644 --- a/pgrx/src/shmem_hash.rs +++ b/pgrx/src/shmem_hash.rs @@ -3,6 +3,7 @@ use crate::shmem::PgSharedMemoryInitialization; use crate::PgSharedMem; use crate::{pg_sys, PGRXSharedMemory}; use uuid::Uuid; +use std::ffi::c_void; #[derive(Debug, Eq, PartialEq)] #[non_exhaustive] @@ -19,6 +20,18 @@ unsafe impl PGRXSharedMemory for PgHashMapInner {} unsafe impl Send for PgHashMapInner {} unsafe impl Sync for PgHashMapInner {} +#[repr(align(8))] +#[derive(Copy, Clone, Debug)] +struct Key { + key: i64, +} + +#[repr(align(8))] +#[derive(Copy, Clone, Debug)] +struct Value { + value: i64, +} + impl Default for PgHashMapInner { fn default() -> Self { Self { htab: std::ptr::null_mut() } @@ -35,14 +48,33 @@ impl PgHashMap { PgHashMap { htab: PgLwLock::new(), size } } - pub fn insert(&self, key: &i64, _value: &i64) { + pub fn insert(&self, key: i64, value: i64) { let htab = self.htab.exclusive(); - let void_ptr: *const core::ffi::c_void = key as *const _ as *const core::ffi::c_void; + // let void_ptr: *const core::ffi::c_void = key as *const i64 as *const core::ffi::c_void; let mut found = false; - let _entry = unsafe { - pg_sys::hash_search(htab.htab, void_ptr, pg_sys::HASHACTION_HASH_ENTER_NULL, &mut found) + let mut key_value = Key { key: 0 }; + unsafe { std::ptr::addr_of_mut!(key_value).write_bytes(0, std::mem::size_of::()) }; + + println!("key: {:?}", key_value); + + key_value.key = key; + + println!("key: {:?}", key_value); + + let key_ptr: *const c_void = std::ptr::addr_of!(key_value) as *const Key as *const c_void; + + println!("Searching key: {:?}", key_ptr); + let entry = unsafe { + pg_sys::hash_search(htab.htab, key_ptr, pg_sys::HASHACTION_HASH_ENTER_NULL, &mut found) }; + + if !entry.is_null() { + let value_ptr: *mut Value = entry as *mut Value; + unsafe { + std::ptr::write(value_ptr, Value { value }); + } + } } } @@ -56,8 +88,8 @@ impl PgSharedMemoryInitialization for PgHashMap { let mut htab = self.htab.exclusive(); let mut hash_ctl = pg_sys::HASHCTL::default(); - hash_ctl.keysize = std::mem::size_of::(); - hash_ctl.entrysize = std::mem::size_of::(); + hash_ctl.keysize = std::mem::size_of::(); + hash_ctl.entrysize = std::mem::size_of::(); let shm_name = alloc::ffi::CString::new(Uuid::new_v4().to_string()).expect("CString::new() failed"); From edd33009f4cc01e396be1823aeb1ca0134979430 Mon Sep 17 00:00:00 2001 From: Lev Kokotov Date: Wed, 8 Nov 2023 09:22:53 -0800 Subject: [PATCH 04/15] clean --- pgrx/src/shmem_hash.rs | 28 +++++++++------------------- 1 file changed, 9 insertions(+), 19 deletions(-) diff --git a/pgrx/src/shmem_hash.rs b/pgrx/src/shmem_hash.rs index e01b1efd9..67169f76a 100644 --- a/pgrx/src/shmem_hash.rs +++ b/pgrx/src/shmem_hash.rs @@ -2,8 +2,8 @@ use crate::lwlock::*; use crate::shmem::PgSharedMemoryInitialization; use crate::PgSharedMem; use crate::{pg_sys, PGRXSharedMemory}; -use uuid::Uuid; use std::ffi::c_void; +use uuid::Uuid; #[derive(Debug, Eq, PartialEq)] #[non_exhaustive] @@ -23,13 +23,13 @@ unsafe impl Sync for PgHashMapInner {} #[repr(align(8))] #[derive(Copy, Clone, Debug)] struct Key { - key: i64, + key: i64, } #[repr(align(8))] #[derive(Copy, Clone, Debug)] struct Value { - value: i64, + value: i64, } impl Default for PgHashMapInner { @@ -50,30 +50,20 @@ impl PgHashMap { pub fn insert(&self, key: i64, value: i64) { let htab = self.htab.exclusive(); - // let void_ptr: *const core::ffi::c_void = key as *const i64 as *const core::ffi::c_void; let mut found = false; - let mut key_value = Key { key: 0 }; - unsafe { std::ptr::addr_of_mut!(key_value).write_bytes(0, std::mem::size_of::()) }; - - println!("key: {:?}", key_value); - - key_value.key = key; - - println!("key: {:?}", key_value); - + let key_value = Key { key }; let key_ptr: *const c_void = std::ptr::addr_of!(key_value) as *const Key as *const c_void; - println!("Searching key: {:?}", key_ptr); let entry = unsafe { - pg_sys::hash_search(htab.htab, key_ptr, pg_sys::HASHACTION_HASH_ENTER_NULL, &mut found) + pg_sys::hash_search(htab.htab, key_ptr, pg_sys::HASHACTION_HASH_ENTER, &mut found) }; if !entry.is_null() { - let value_ptr: *mut Value = entry as *mut Value; - unsafe { - std::ptr::write(value_ptr, Value { value }); - } + let value_ptr: *mut Value = entry as *mut Value; + unsafe { + std::ptr::write(value_ptr, Value { value }); + } } } } From f47615ac46c1795c3e3408850c41f722a1a628fb Mon Sep 17 00:00:00 2001 From: Lev Kokotov Date: Wed, 8 Nov 2023 15:50:48 -0800 Subject: [PATCH 05/15] alright! --- pgrx-examples/shmem/src/lib.rs | 16 +++- pgrx/src/shmem_hash.rs | 151 ++++++++++++++++++++++++++++----- 2 files changed, 145 insertions(+), 22 deletions(-) diff --git a/pgrx-examples/shmem/src/lib.rs b/pgrx-examples/shmem/src/lib.rs index e0d399bfe..2916c28b4 100644 --- a/pgrx-examples/shmem/src/lib.rs +++ b/pgrx-examples/shmem/src/lib.rs @@ -40,7 +40,7 @@ static HASH: PgLwLock> = PgLwLock::new(); static STRUCT: PgLwLock = PgLwLock::new(); static PRIMITIVE: PgLwLock = PgLwLock::new(); static ATOMIC: PgAtomic = PgAtomic::new(); -static HASH_TABLE: PgHashMap = PgHashMap::new(25); +static HASH_TABLE: PgHashMap = PgHashMap::new(2); #[pg_guard] pub extern "C" fn _PG_init() { @@ -64,8 +64,18 @@ fn vec_count() -> i32 { } #[pg_extern] -fn hash_table_insert(key: i64, value: i64) { - HASH_TABLE.insert(key, value); +fn hash_table_insert(key: i64, value: f32) { + HASH_TABLE.insert(key, value).unwrap(); +} + +#[pg_extern] +fn hash_table_get(key: i64) -> Option { + HASH_TABLE.get(key) +} + +#[pg_extern] +fn hash_table_remove(key: i64) -> Option { + HASH_TABLE.remove(key) } #[pg_extern] diff --git a/pgrx/src/shmem_hash.rs b/pgrx/src/shmem_hash.rs index 67169f76a..48a0b6b2c 100644 --- a/pgrx/src/shmem_hash.rs +++ b/pgrx/src/shmem_hash.rs @@ -14,6 +14,7 @@ pub enum Error { #[derive(Copy, Clone)] pub struct PgHashMapInner { htab: *mut pg_sys::HTAB, + elements: u64, } unsafe impl PGRXSharedMemory for PgHashMapInner {} @@ -22,53 +23,165 @@ unsafe impl Sync for PgHashMapInner {} #[repr(align(8))] #[derive(Copy, Clone, Debug)] -struct Key { - key: i64, +struct Key { + // We copy it with std::ptr::copy, but we don't actually use the field + // in Rust, hence the warning. + #[allow(dead_code)] + key: K, } #[repr(align(8))] #[derive(Copy, Clone, Debug)] -struct Value { - value: i64, +struct Value { + value: V, } impl Default for PgHashMapInner { fn default() -> Self { - Self { htab: std::ptr::null_mut() } + Self { htab: std::ptr::null_mut(), elements: 0 } } } -pub struct PgHashMap { +pub struct PgHashMap { htab: PgLwLock, size: u64, + phantom_key: std::marker::PhantomData, + phantom_value: std::marker::PhantomData, } -impl PgHashMap { - pub const fn new(size: u64) -> PgHashMap { - PgHashMap { htab: PgLwLock::new(), size } +/// Compute the hash for the key and it's pointer +/// to pass to the hash_search. Lock on HTAB should be taken, +/// although not strictly required I think. +macro_rules! key { + ($key:expr, $htab:expr) => {{ + let key = Key { key: $key }; + let key_ptr: *const c_void = std::ptr::addr_of!(key) as *const Key as *const c_void; + let hash_value = unsafe { pg_sys::get_hash_value($htab.htab, key_ptr) }; + + (key_ptr, hash_value) + }}; +} + +/// Get the value pointer. It's stored next to the key. +/// https://github.com/postgres/postgres/blob/1f998863b0bc6fc8ef3d971d9c6d2c29b52d8ba2/src/backend/utils/hash/dynahash.c#L246-L250 +macro_rules! value_ptr { + ($entry:expr) => {{ + let value_ptr: *mut Value = + unsafe { $entry.offset(std::mem::size_of::>().try_into().unwrap()) } + as *mut Value; + + value_ptr + }}; +} + +impl PgHashMap { + /// Create new PgHashMap. This still needs to be allocated with + /// `pg_shmem_init!` just like any other shared memory structure. + pub const fn new(size: u64) -> PgHashMap { + PgHashMap { + htab: PgLwLock::new(), + size, + phantom_key: std::marker::PhantomData, + phantom_value: std::marker::PhantomData, + } } - pub fn insert(&self, key: i64, value: i64) { - let htab = self.htab.exclusive(); + /// Insert a key and value into the HashMap. If the key is already + /// present, it will be replaced. If the HashMap is full, return an error. + pub fn insert(&self, key: K, value: V) -> Result<(), Error> { let mut found = false; + let mut htab = self.htab.exclusive(); + let (key_ptr, hash_value) = key!(key, htab); + + let entry = unsafe { + pg_sys::hash_search_with_hash_value( + htab.htab, + key_ptr, + hash_value, + pg_sys::HASHACTION_HASH_FIND, + &mut found, + ) + }; - let key_value = Key { key }; - let key_ptr: *const c_void = std::ptr::addr_of!(key_value) as *const Key as *const c_void; + if entry.is_null() && htab.elements == self.size { + return Err(Error::HashTableFull); + } let entry = unsafe { - pg_sys::hash_search(htab.htab, key_ptr, pg_sys::HASHACTION_HASH_ENTER, &mut found) + pg_sys::hash_search_with_hash_value( + htab.htab, + key_ptr, + hash_value, + pg_sys::HASHACTION_HASH_ENTER_NULL, + &mut found, + ) }; if !entry.is_null() { - let value_ptr: *mut Value = entry as *mut Value; + let value_ptr = value_ptr!(entry); + let value = Value { value }; unsafe { - std::ptr::write(value_ptr, Value { value }); + std::ptr::copy(std::ptr::addr_of!(value), value_ptr, 1); } + htab.elements += 1; + Ok(()) + } else { + // OOM. + return Err(Error::HashTableFull); + } + } + + /// Get a value from the HashMap using the key. + /// If the key doesn't exist, return None. + pub fn get(&self, key: K) -> Option { + let htab = self.htab.exclusive(); + let (key_ptr, hash_value) = key!(key, htab); + + let entry = unsafe { + pg_sys::hash_search_with_hash_value( + htab.htab, + key_ptr, + hash_value, + pg_sys::HASHACTION_HASH_FIND, + std::ptr::null_mut(), + ) + }; + + if entry.is_null() { + return None; + } else { + let value_ptr = value_ptr!(entry); + let value = unsafe { std::ptr::read(value_ptr) }; + return Some(value.value); + } + } + + /// Remove the value from the HashMap and return it. + pub fn remove(&self, key: K) -> Option { + if let Some(value) = self.get(key) { + let mut htab = self.htab.exclusive(); + let (key_ptr, hash_value) = key!(key, htab); + + // Dangling pointer, don't touch it. + let _ = unsafe { + pg_sys::hash_search_with_hash_value( + htab.htab, + key_ptr, + hash_value, + pg_sys::HASHACTION_HASH_REMOVE, + std::ptr::null_mut(), + ); + }; + + htab.elements -= 1; + return Some(value); + } else { + return None; } } } -impl PgSharedMemoryInitialization for PgHashMap { +impl PgSharedMemoryInitialization for PgHashMap { fn pg_init(&'static self) { PgSharedMem::pg_init_locked(&self.htab); } @@ -78,8 +191,8 @@ impl PgSharedMemoryInitialization for PgHashMap { let mut htab = self.htab.exclusive(); let mut hash_ctl = pg_sys::HASHCTL::default(); - hash_ctl.keysize = std::mem::size_of::(); - hash_ctl.entrysize = std::mem::size_of::(); + hash_ctl.keysize = std::mem::size_of::>(); + hash_ctl.entrysize = std::mem::size_of::>(); let shm_name = alloc::ffi::CString::new(Uuid::new_v4().to_string()).expect("CString::new() failed"); From b69a6dcda8756d3fbd7f213f9f6edbd1bc3af9b7 Mon Sep 17 00:00:00 2001 From: Lev Kokotov Date: Wed, 8 Nov 2023 15:53:17 -0800 Subject: [PATCH 06/15] alright! --- pgrx-examples/shmem/src/lib.rs | 5 +++++ pgrx/src/shmem_hash.rs | 6 ++++++ 2 files changed, 11 insertions(+) diff --git a/pgrx-examples/shmem/src/lib.rs b/pgrx-examples/shmem/src/lib.rs index 2916c28b4..81d76d8d0 100644 --- a/pgrx-examples/shmem/src/lib.rs +++ b/pgrx-examples/shmem/src/lib.rs @@ -78,6 +78,11 @@ fn hash_table_remove(key: i64) -> Option { HASH_TABLE.remove(key) } +#[pg_extern] +fn hash_table_len() -> i64 { + HASH_TABLE.len() as i64 +} + #[pg_extern] fn vec_drain() -> SetOfIterator<'static, Pgtest> { let mut vec = VEC.exclusive(); diff --git a/pgrx/src/shmem_hash.rs b/pgrx/src/shmem_hash.rs index 48a0b6b2c..66b587cd7 100644 --- a/pgrx/src/shmem_hash.rs +++ b/pgrx/src/shmem_hash.rs @@ -179,6 +179,12 @@ impl PgHashMap { return None; } } + + /// Get the number of elements in the HashMap. + pub fn len(&self) -> usize { + let htab = self.htab.exclusive(); + htab.elements.try_into().unwrap() + } } impl PgSharedMemoryInitialization for PgHashMap { From a168537e5c74207aeb9b7aa8c7845ef30b914d65 Mon Sep 17 00:00:00 2001 From: Lev Kokotov Date: Wed, 8 Nov 2023 15:55:01 -0800 Subject: [PATCH 07/15] comment --- pgrx/src/shmem_hash.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pgrx/src/shmem_hash.rs b/pgrx/src/shmem_hash.rs index 66b587cd7..02262736f 100644 --- a/pgrx/src/shmem_hash.rs +++ b/pgrx/src/shmem_hash.rs @@ -103,6 +103,8 @@ impl PgHashMap { ) }; + // If we don't do this check, pg will overwrite + // some random entry with our key/value... if entry.is_null() && htab.elements == self.size { return Err(Error::HashTableFull); } From 8ccbd745034f9900d14c7f6595358e4b4128ec71 Mon Sep 17 00:00:00 2001 From: Lev Date: Thu, 9 Nov 2023 09:13:28 -0800 Subject: [PATCH 08/15] tests --- pgrx-examples/shmem/insert.sql | 2 + pgrx-examples/shmem/src/lib.rs | 10 ++-- pgrx-tests/src/tests/shmem_hash_tests.rs | 26 ++++++++++ pgrx-tests/src/tests/shmem_tests.rs | 14 +++++- pgrx/src/lib.rs | 1 + pgrx/src/shmem_hash.rs | 62 ++++++++++++++++-------- 6 files changed, 89 insertions(+), 26 deletions(-) create mode 100644 pgrx-examples/shmem/insert.sql create mode 100644 pgrx-tests/src/tests/shmem_hash_tests.rs diff --git a/pgrx-examples/shmem/insert.sql b/pgrx-examples/shmem/insert.sql new file mode 100644 index 000000000..eded1b989 --- /dev/null +++ b/pgrx-examples/shmem/insert.sql @@ -0,0 +1,2 @@ +\set u random(1, 50) +select hash_table_insert(:u, :u); diff --git a/pgrx-examples/shmem/src/lib.rs b/pgrx-examples/shmem/src/lib.rs index 81d76d8d0..862af5534 100644 --- a/pgrx-examples/shmem/src/lib.rs +++ b/pgrx-examples/shmem/src/lib.rs @@ -40,7 +40,7 @@ static HASH: PgLwLock> = PgLwLock::new(); static STRUCT: PgLwLock = PgLwLock::new(); static PRIMITIVE: PgLwLock = PgLwLock::new(); static ATOMIC: PgAtomic = PgAtomic::new(); -static HASH_TABLE: PgHashMap = PgHashMap::new(2); +static HASH_TABLE: PgHashMap = PgHashMap::new(250); #[pg_guard] pub extern "C" fn _PG_init() { @@ -64,17 +64,17 @@ fn vec_count() -> i32 { } #[pg_extern] -fn hash_table_insert(key: i64, value: f32) { - HASH_TABLE.insert(key, value).unwrap(); +fn hash_table_insert(key: i64, value: i64) -> Option { + HASH_TABLE.insert(key, value).unwrap() } #[pg_extern] -fn hash_table_get(key: i64) -> Option { +fn hash_table_get(key: i64) -> Option { HASH_TABLE.get(key) } #[pg_extern] -fn hash_table_remove(key: i64) -> Option { +fn hash_table_remove(key: i64) -> Option { HASH_TABLE.remove(key) } diff --git a/pgrx-tests/src/tests/shmem_hash_tests.rs b/pgrx-tests/src/tests/shmem_hash_tests.rs new file mode 100644 index 000000000..539d35fd2 --- /dev/null +++ b/pgrx-tests/src/tests/shmem_hash_tests.rs @@ -0,0 +1,26 @@ +use pgrx::prelude::*; +use pgrx::{pg_shmem_init, PgHashMap, PgSharedMemoryInitialization}; + +static HASH_MAP: PgHashMap = PgHashMap::new(250); + +#[pg_guard] +pub extern "C" fn _PG_init() { + // This ensures that this functionality works across PostgreSQL versions + pg_shmem_init!(HASH_MAP); +} + +#[cfg(any(test, feature = "pg_test"))] +#[pgrx::pg_schema] +mod tests { + #[allow(unused_imports)] + use crate as pgrx_tests; + + use super::*; + + #[pg_test] + pub fn test_insert() { + for i in 0..250 { + assert_eq!(HASH_MAP.insert(i, i), Ok(None)); + } + } +} diff --git a/pgrx-tests/src/tests/shmem_tests.rs b/pgrx-tests/src/tests/shmem_tests.rs index 353d8e363..9f339e700 100644 --- a/pgrx-tests/src/tests/shmem_tests.rs +++ b/pgrx-tests/src/tests/shmem_tests.rs @@ -8,25 +8,28 @@ //LICENSE //LICENSE Use of this source code is governed by the MIT license that can be found in the LICENSE file. use pgrx::prelude::*; -use pgrx::{pg_shmem_init, PgAtomic, PgLwLock, PgSharedMemoryInitialization}; +use pgrx::{pg_shmem_init, PgAtomic, PgHashMap, PgLwLock, PgSharedMemoryInitialization}; use std::sync::atomic::AtomicBool; static ATOMIC: PgAtomic = PgAtomic::new(); static LWLOCK: PgLwLock = PgLwLock::new(); +static HASH_MAP: PgHashMap = PgHashMap::new(250); #[pg_guard] pub extern "C" fn _PG_init() { // This ensures that this functionality works across PostgreSQL versions pg_shmem_init!(ATOMIC); pg_shmem_init!(LWLOCK); + pg_shmem_init!(HASH_MAP); } + #[cfg(any(test, feature = "pg_test"))] #[pgrx::pg_schema] mod tests { #[allow(unused_imports)] use crate as pgrx_tests; - use crate::tests::shmem_tests::LWLOCK; + use crate::tests::shmem_tests::{HASH_MAP, LWLOCK}; use pgrx::prelude::*; #[pg_test] @@ -53,4 +56,11 @@ mod tests { }); let _lock = LWLOCK.exclusive(); } + + #[pg_test] + pub fn test_pg_hash_map_insert() { + for i in 1..250 { + assert_eq!(HASH_MAP.insert(i, i), Ok(None)); + } + } } diff --git a/pgrx/src/lib.rs b/pgrx/src/lib.rs index 8ae00ec77..7d142a1a3 100644 --- a/pgrx/src/lib.rs +++ b/pgrx/src/lib.rs @@ -107,6 +107,7 @@ pub use nodes::*; pub use pgbox::*; pub use rel::*; pub use shmem::*; +pub use shmem_hash::*; pub use spi::Spi; // only Spi. We don't want the top-level namespace polluted with spi::Result and spi::Error pub use stringinfo::*; pub use trigger_support::*; diff --git a/pgrx/src/shmem_hash.rs b/pgrx/src/shmem_hash.rs index 02262736f..76fa19650 100644 --- a/pgrx/src/shmem_hash.rs +++ b/pgrx/src/shmem_hash.rs @@ -1,7 +1,7 @@ -use crate::lwlock::*; -use crate::shmem::PgSharedMemoryInitialization; -use crate::PgSharedMem; -use crate::{pg_sys, PGRXSharedMemory}; +use crate::{ + lwlock::*, pg_sys, shmem::PgSharedMemoryInitialization, PGRXSharedMemory, PgSharedMem, +}; + use std::ffi::c_void; use uuid::Uuid; @@ -12,7 +12,7 @@ pub enum Error { } #[derive(Copy, Clone)] -pub struct PgHashMapInner { +struct PgHashMapInner { htab: *mut pg_sys::HTAB, elements: u64, } @@ -42,16 +42,24 @@ impl Default for PgHashMapInner { } } +/// A shared memory HashMap using Postgres' `HTAB`. +/// This HashMap is used for `pg_stat_statements` and Postgres +/// internals to store key/value pairs in shared memory. pub struct PgHashMap { + /// HTAB protected by a LwLock. htab: PgLwLock, + + /// Max size, allocated at server start. size: u64, + + // Markers for key/value types. phantom_key: std::marker::PhantomData, phantom_value: std::marker::PhantomData, } -/// Compute the hash for the key and it's pointer -/// to pass to the hash_search. Lock on HTAB should be taken, -/// although not strictly required I think. +/// Compute the hash for the key and its pointer +/// to pass to `pg_sys::hash_search_with_hash_value`. +/// Lock on HTAB should be taken, although not strictly required I think. macro_rules! key { ($key:expr, $htab:expr) => {{ let key = Key { key: $key }; @@ -63,7 +71,8 @@ macro_rules! key { } /// Get the value pointer. It's stored next to the key. -/// https://github.com/postgres/postgres/blob/1f998863b0bc6fc8ef3d971d9c6d2c29b52d8ba2/src/backend/utils/hash/dynahash.c#L246-L250 +/// See: +/// for implementation. `pg_stat_statements` stores the key in the value struct, but this works too. macro_rules! value_ptr { ($entry:expr) => {{ let value_ptr: *mut Value = @@ -75,7 +84,7 @@ macro_rules! value_ptr { } impl PgHashMap { - /// Create new PgHashMap. This still needs to be allocated with + /// Create new `PgHashMap`. This still needs to be allocated with /// `pg_shmem_init!` just like any other shared memory structure. pub const fn new(size: u64) -> PgHashMap { PgHashMap { @@ -86,13 +95,14 @@ impl PgHashMap { } } - /// Insert a key and value into the HashMap. If the key is already - /// present, it will be replaced. If the HashMap is full, return an error. - pub fn insert(&self, key: K, value: V) -> Result<(), Error> { + /// Insert a key and value into the `PgHashMap`. If the key is already + /// present, it will be replaced and returned. If the `PgHashMap` is full, return an error. + pub fn insert(&self, key: K, value: V) -> Result, Error> { let mut found = false; let mut htab = self.htab.exclusive(); let (key_ptr, hash_value) = key!(key, htab); + println!("Find"); let entry = unsafe { pg_sys::hash_search_with_hash_value( htab.htab, @@ -103,12 +113,24 @@ impl PgHashMap { ) }; + println!("Done find"); + + let return_value = if entry.is_null() { + None + } else { + println!("Found"); + let value_ptr = value_ptr!(entry); + let value = unsafe { std::ptr::read(value_ptr) }; + Some(value.value) + }; + // If we don't do this check, pg will overwrite - // some random entry with our key/value... + // some random entry with our key/value pair... if entry.is_null() && htab.elements == self.size { return Err(Error::HashTableFull); } + println!("Replace"); let entry = unsafe { pg_sys::hash_search_with_hash_value( htab.htab, @@ -122,13 +144,14 @@ impl PgHashMap { if !entry.is_null() { let value_ptr = value_ptr!(entry); let value = Value { value }; + println!("Insert"); unsafe { std::ptr::copy(std::ptr::addr_of!(value), value_ptr, 1); } htab.elements += 1; - Ok(()) + Ok(return_value) } else { - // OOM. + // OOM. We pre-allocate at server start, so this should never be an issue. return Err(Error::HashTableFull); } } @@ -158,7 +181,8 @@ impl PgHashMap { } } - /// Remove the value from the HashMap and return it. + /// Remove the value from the `PgHashMap` and return it. + /// If the key doesn't exist, return None. pub fn remove(&self, key: K) -> Option { if let Some(value) = self.get(key) { let mut htab = self.htab.exclusive(); @@ -183,9 +207,9 @@ impl PgHashMap { } /// Get the number of elements in the HashMap. - pub fn len(&self) -> usize { + pub fn len(&self) -> u64 { let htab = self.htab.exclusive(); - htab.elements.try_into().unwrap() + htab.elements } } From 6e088de6ccf61898fad5f4a5c2c3056b073c6897 Mon Sep 17 00:00:00 2001 From: Lev Date: Thu, 9 Nov 2023 09:49:31 -0800 Subject: [PATCH 09/15] alright! --- pgrx-examples/shmem/insert.sql | 1478 +++++++++++++++++++++- pgrx-tests/src/tests/shmem_hash_tests.rs | 26 - pgrx-tests/src/tests/shmem_tests.rs | 47 +- pgrx/src/shmem_hash.rs | 29 +- 4 files changed, 1533 insertions(+), 47 deletions(-) delete mode 100644 pgrx-tests/src/tests/shmem_hash_tests.rs diff --git a/pgrx-examples/shmem/insert.sql b/pgrx-examples/shmem/insert.sql index eded1b989..b37ad3cd5 100644 --- a/pgrx-examples/shmem/insert.sql +++ b/pgrx-examples/shmem/insert.sql @@ -1,2 +1,1476 @@ -\set u random(1, 50) -select hash_table_insert(:u, :u); + +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); + +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); + +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); + +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); + +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); + +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); + +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); + +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); + +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); + +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); + +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); + +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); + +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); + +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); + +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); + +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); + +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); + +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); + +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); + +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); + +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); + +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); + +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); + +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); + +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); + +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); + +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); + +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); + +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); + +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); + +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); + +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); + +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); + +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); + +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); + +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); +select hash_table_insert(25, 25); diff --git a/pgrx-tests/src/tests/shmem_hash_tests.rs b/pgrx-tests/src/tests/shmem_hash_tests.rs deleted file mode 100644 index 539d35fd2..000000000 --- a/pgrx-tests/src/tests/shmem_hash_tests.rs +++ /dev/null @@ -1,26 +0,0 @@ -use pgrx::prelude::*; -use pgrx::{pg_shmem_init, PgHashMap, PgSharedMemoryInitialization}; - -static HASH_MAP: PgHashMap = PgHashMap::new(250); - -#[pg_guard] -pub extern "C" fn _PG_init() { - // This ensures that this functionality works across PostgreSQL versions - pg_shmem_init!(HASH_MAP); -} - -#[cfg(any(test, feature = "pg_test"))] -#[pgrx::pg_schema] -mod tests { - #[allow(unused_imports)] - use crate as pgrx_tests; - - use super::*; - - #[pg_test] - pub fn test_insert() { - for i in 0..250 { - assert_eq!(HASH_MAP.insert(i, i), Ok(None)); - } - } -} diff --git a/pgrx-tests/src/tests/shmem_tests.rs b/pgrx-tests/src/tests/shmem_tests.rs index 9f339e700..460a3f7ee 100644 --- a/pgrx-tests/src/tests/shmem_tests.rs +++ b/pgrx-tests/src/tests/shmem_tests.rs @@ -13,7 +13,7 @@ use std::sync::atomic::AtomicBool; static ATOMIC: PgAtomic = PgAtomic::new(); static LWLOCK: PgLwLock = PgLwLock::new(); -static HASH_MAP: PgHashMap = PgHashMap::new(250); +static HASH_MAP: PgHashMap = PgHashMap::new(500); #[pg_guard] pub extern "C" fn _PG_init() { @@ -58,9 +58,52 @@ mod tests { } #[pg_test] - pub fn test_pg_hash_map_insert() { + pub fn test_pg_hash_map() { + use rand::prelude::IteratorRandom; + for i in 1..250 { assert_eq!(HASH_MAP.insert(i, i), Ok(None)); } + + assert_eq!(HASH_MAP.len(), 249); + + for i in 1..250 { + assert_eq!(HASH_MAP.get(i), Some(i)); + } + + assert_eq!(HASH_MAP.len(), 249); + + for i in 251..500 { + assert_eq!(HASH_MAP.get(i), None); + } + + assert_eq!(HASH_MAP.len(), 249); + + for i in 1..250 { + assert_eq!(HASH_MAP.insert(i, i), Ok(Some(i))); + } + + assert_eq!(HASH_MAP.len(), 249); + + for i in 1..250 { + assert_eq!(HASH_MAP.remove(i), Some(i)); + } + + assert_eq!(HASH_MAP.len(), 0); + + for i in 1..250 { + assert_eq!(HASH_MAP.get(i), None); + } + + assert_eq!(HASH_MAP.len(), 0); + + for _ in 0..25_000 { + for key in 0..250 { + let value = (0..1000).choose(&mut rand::thread_rng()).unwrap(); + assert!(HASH_MAP.insert(key, value).is_ok()); + } + } + + assert_eq!(HASH_MAP.len(), 250); } } diff --git a/pgrx/src/shmem_hash.rs b/pgrx/src/shmem_hash.rs index 76fa19650..68046c758 100644 --- a/pgrx/src/shmem_hash.rs +++ b/pgrx/src/shmem_hash.rs @@ -21,7 +21,7 @@ unsafe impl PGRXSharedMemory for PgHashMapInner {} unsafe impl Send for PgHashMapInner {} unsafe impl Sync for PgHashMapInner {} -#[repr(align(8))] +// #[repr(align(8))] #[derive(Copy, Clone, Debug)] struct Key { // We copy it with std::ptr::copy, but we don't actually use the field @@ -30,9 +30,11 @@ struct Key { key: K, } -#[repr(align(8))] +// #[repr(align(8))] #[derive(Copy, Clone, Debug)] -struct Value { +struct Value { + #[allow(dead_code)] + key: Key, value: V, } @@ -71,13 +73,9 @@ macro_rules! key { } /// Get the value pointer. It's stored next to the key. -/// See: -/// for implementation. `pg_stat_statements` stores the key in the value struct, but this works too. macro_rules! value_ptr { ($entry:expr) => {{ - let value_ptr: *mut Value = - unsafe { $entry.offset(std::mem::size_of::>().try_into().unwrap()) } - as *mut Value; + let value_ptr: *mut Value = $entry as *mut Value; value_ptr }}; @@ -102,7 +100,6 @@ impl PgHashMap { let mut htab = self.htab.exclusive(); let (key_ptr, hash_value) = key!(key, htab); - println!("Find"); let entry = unsafe { pg_sys::hash_search_with_hash_value( htab.htab, @@ -113,12 +110,9 @@ impl PgHashMap { ) }; - println!("Done find"); - let return_value = if entry.is_null() { None } else { - println!("Found"); let value_ptr = value_ptr!(entry); let value = unsafe { std::ptr::read(value_ptr) }; Some(value.value) @@ -130,7 +124,6 @@ impl PgHashMap { return Err(Error::HashTableFull); } - println!("Replace"); let entry = unsafe { pg_sys::hash_search_with_hash_value( htab.htab, @@ -143,12 +136,14 @@ impl PgHashMap { if !entry.is_null() { let value_ptr = value_ptr!(entry); - let value = Value { value }; - println!("Insert"); + let value = Value { key: Key { key }, value }; unsafe { std::ptr::copy(std::ptr::addr_of!(value), value_ptr, 1); } - htab.elements += 1; + // We inserted a new element, increasing the size of the table. + if return_value.is_none() { + htab.elements += 1; + } Ok(return_value) } else { // OOM. We pre-allocate at server start, so this should never be an issue. @@ -224,7 +219,7 @@ impl PgSharedMemoryInitialization for PgHashMa let mut hash_ctl = pg_sys::HASHCTL::default(); hash_ctl.keysize = std::mem::size_of::>(); - hash_ctl.entrysize = std::mem::size_of::>(); + hash_ctl.entrysize = std::mem::size_of::>(); let shm_name = alloc::ffi::CString::new(Uuid::new_v4().to_string()).expect("CString::new() failed"); From f490b9965988fef9fb16084c717c5e0b3e119c13 Mon Sep 17 00:00:00 2001 From: Lev Date: Thu, 9 Nov 2023 09:50:08 -0800 Subject: [PATCH 10/15] remove --- pgrx-examples/shmem/insert.sql | 1476 -------------------------------- 1 file changed, 1476 deletions(-) delete mode 100644 pgrx-examples/shmem/insert.sql diff --git a/pgrx-examples/shmem/insert.sql b/pgrx-examples/shmem/insert.sql deleted file mode 100644 index b37ad3cd5..000000000 --- a/pgrx-examples/shmem/insert.sql +++ /dev/null @@ -1,1476 +0,0 @@ - -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); - -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); - -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); - -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); - -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); - -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); - -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); - -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); - -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); - -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); - -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); - -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); - -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); - -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); - -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); - -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); - -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); - -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); - -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); - -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); - -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); - -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); - -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); - -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); - -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); - -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); - -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); - -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); - -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); - -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); - -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); - -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); - -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); - -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); - -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); - -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); -select hash_table_insert(25, 25); From fe95ef329b4232845ba95a1929767363d8a6ee18 Mon Sep 17 00:00:00 2001 From: Lev Kokotov Date: Sat, 18 Nov 2023 10:01:12 -0800 Subject: [PATCH 11/15] finish up hashmap --- pgrx-examples/shmem/Cargo.toml | 2 +- pgrx/src/lib.rs | 1 + pgrx/src/shmem_hash.rs | 37 ++++++++++++++++------------------ pgrx/src/spinlock.rs | 1 + 4 files changed, 20 insertions(+), 21 deletions(-) diff --git a/pgrx-examples/shmem/Cargo.toml b/pgrx-examples/shmem/Cargo.toml index 86ed554c6..8c85221fd 100644 --- a/pgrx-examples/shmem/Cargo.toml +++ b/pgrx-examples/shmem/Cargo.toml @@ -17,7 +17,7 @@ edition = "2021" crate-type = ["cdylib"] [features] -default = ["pg13"] +default = ["pg13", "pgrx/cshim"] pg12 = ["pgrx/pg12", "pgrx-tests/pg12" ] pg13 = ["pgrx/pg13", "pgrx-tests/pg13" ] pg14 = ["pgrx/pg14", "pgrx-tests/pg14" ] diff --git a/pgrx/src/lib.rs b/pgrx/src/lib.rs index 7d142a1a3..edaecfe08 100644 --- a/pgrx/src/lib.rs +++ b/pgrx/src/lib.rs @@ -65,6 +65,7 @@ pub mod pg_catalog; pub mod pgbox; pub mod rel; pub mod shmem; +#[cfg(feature = "cshim")] pub mod shmem_hash; pub mod spi; #[cfg(feature = "cshim")] diff --git a/pgrx/src/shmem_hash.rs b/pgrx/src/shmem_hash.rs index 68046c758..c3e1b2790 100644 --- a/pgrx/src/shmem_hash.rs +++ b/pgrx/src/shmem_hash.rs @@ -1,7 +1,5 @@ -use crate::{ - lwlock::*, pg_sys, shmem::PgSharedMemoryInitialization, PGRXSharedMemory, PgSharedMem, -}; - +use crate::{pg_sys, shmem::PgSharedMemoryInitialization, spinlock::*, PGRXSharedMemory}; +use once_cell::sync::OnceCell; use std::ffi::c_void; use uuid::Uuid; @@ -11,7 +9,7 @@ pub enum Error { HashTableFull, } -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Debug)] struct PgHashMapInner { htab: *mut pg_sys::HTAB, elements: u64, @@ -21,7 +19,7 @@ unsafe impl PGRXSharedMemory for PgHashMapInner {} unsafe impl Send for PgHashMapInner {} unsafe impl Sync for PgHashMapInner {} -// #[repr(align(8))] +#[repr(C)] #[derive(Copy, Clone, Debug)] struct Key { // We copy it with std::ptr::copy, but we don't actually use the field @@ -30,7 +28,7 @@ struct Key { key: K, } -// #[repr(align(8))] +#[repr(C)] #[derive(Copy, Clone, Debug)] struct Value { #[allow(dead_code)] @@ -49,14 +47,14 @@ impl Default for PgHashMapInner { /// internals to store key/value pairs in shared memory. pub struct PgHashMap { /// HTAB protected by a LwLock. - htab: PgLwLock, + htab: OnceCell>, /// Max size, allocated at server start. size: u64, // Markers for key/value types. - phantom_key: std::marker::PhantomData, - phantom_value: std::marker::PhantomData, + _phantom_key: std::marker::PhantomData, + _phantom_value: std::marker::PhantomData, } /// Compute the hash for the key and its pointer @@ -86,10 +84,10 @@ impl PgHashMap { /// `pg_shmem_init!` just like any other shared memory structure. pub const fn new(size: u64) -> PgHashMap { PgHashMap { - htab: PgLwLock::new(), + htab: OnceCell::new(), size, - phantom_key: std::marker::PhantomData, - phantom_value: std::marker::PhantomData, + _phantom_key: std::marker::PhantomData, + _phantom_value: std::marker::PhantomData, } } @@ -97,7 +95,7 @@ impl PgHashMap { /// present, it will be replaced and returned. If the `PgHashMap` is full, return an error. pub fn insert(&self, key: K, value: V) -> Result, Error> { let mut found = false; - let mut htab = self.htab.exclusive(); + let mut htab = self.htab.get().unwrap().lock(); let (key_ptr, hash_value) = key!(key, htab); let entry = unsafe { @@ -154,7 +152,7 @@ impl PgHashMap { /// Get a value from the HashMap using the key. /// If the key doesn't exist, return None. pub fn get(&self, key: K) -> Option { - let htab = self.htab.exclusive(); + let htab = self.htab.get().unwrap().lock(); let (key_ptr, hash_value) = key!(key, htab); let entry = unsafe { @@ -180,7 +178,7 @@ impl PgHashMap { /// If the key doesn't exist, return None. pub fn remove(&self, key: K) -> Option { if let Some(value) = self.get(key) { - let mut htab = self.htab.exclusive(); + let mut htab = self.htab.get().unwrap().lock(); let (key_ptr, hash_value) = key!(key, htab); // Dangling pointer, don't touch it. @@ -203,19 +201,18 @@ impl PgHashMap { /// Get the number of elements in the HashMap. pub fn len(&self) -> u64 { - let htab = self.htab.exclusive(); + let htab = self.htab.get().unwrap().lock(); htab.elements } } impl PgSharedMemoryInitialization for PgHashMap { fn pg_init(&'static self) { - PgSharedMem::pg_init_locked(&self.htab); + self.htab.set(PgSpinLock::new(PgHashMapInner::default())).expect("htab cell is not empty"); } fn shmem_init(&'static self) { - PgSharedMem::shmem_init_locked(&self.htab); - let mut htab = self.htab.exclusive(); + let mut htab = self.htab.get().unwrap().lock(); let mut hash_ctl = pg_sys::HASHCTL::default(); hash_ctl.keysize = std::mem::size_of::>(); diff --git a/pgrx/src/spinlock.rs b/pgrx/src/spinlock.rs index c6a8f5e06..90b56ca95 100644 --- a/pgrx/src/spinlock.rs +++ b/pgrx/src/spinlock.rs @@ -28,6 +28,7 @@ use std::{cell::UnsafeCell, marker::PhantomData}; /// [`storage/spin.h`]: /// https://github.com/postgres/postgres/blob/1f0c4fa255253d223447c2383ad2b384a6f05854/src/include/storage/spin.h #[doc(alias = "slock_t")] +#[derive(Debug)] pub struct PgSpinLock { item: UnsafeCell, lock: UnsafeCell, From cd9d6cc7d99444919a0237172af98854676f81e7 Mon Sep 17 00:00:00 2001 From: Lev Kokotov Date: Sat, 18 Nov 2023 10:09:50 -0800 Subject: [PATCH 12/15] comment --- pgrx/src/shmem_hash.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pgrx/src/shmem_hash.rs b/pgrx/src/shmem_hash.rs index c3e1b2790..cbbacdf86 100644 --- a/pgrx/src/shmem_hash.rs +++ b/pgrx/src/shmem_hash.rs @@ -1,3 +1,5 @@ +//! Shared memory hash map implemented with Postgres' internal `HTAB`, +//! which is used by other extensions like `pg_stat_statements`. use crate::{pg_sys, shmem::PgSharedMemoryInitialization, spinlock::*, PGRXSharedMemory}; use once_cell::sync::OnceCell; use std::ffi::c_void; @@ -6,6 +8,7 @@ use uuid::Uuid; #[derive(Debug, Eq, PartialEq)] #[non_exhaustive] pub enum Error { + /// Hash table can't have more entries due to fixed allocation size. HashTableFull, } @@ -46,7 +49,7 @@ impl Default for PgHashMapInner { /// This HashMap is used for `pg_stat_statements` and Postgres /// internals to store key/value pairs in shared memory. pub struct PgHashMap { - /// HTAB protected by a LwLock. + /// HTAB protected by a SpinLock. htab: OnceCell>, /// Max size, allocated at server start. From 34760d295273106a00b187ab3693c36ee65d9082 Mon Sep 17 00:00:00 2001 From: Lev Date: Mon, 27 Nov 2023 10:40:21 -0800 Subject: [PATCH 13/15] Feature flag --- pgrx/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/pgrx/src/lib.rs b/pgrx/src/lib.rs index edaecfe08..ea49e4357 100644 --- a/pgrx/src/lib.rs +++ b/pgrx/src/lib.rs @@ -108,6 +108,7 @@ pub use nodes::*; pub use pgbox::*; pub use rel::*; pub use shmem::*; +#[cfg(feature = "cshim")] pub use shmem_hash::*; pub use spi::Spi; // only Spi. We don't want the top-level namespace polluted with spi::Result and spi::Error pub use stringinfo::*; From 87558bc712c2c1470a26af1159932520fef74aae Mon Sep 17 00:00:00 2001 From: Lev Date: Mon, 27 Nov 2023 11:02:50 -0800 Subject: [PATCH 14/15] Almost! --- pgrx-tests/src/tests/shmem_tests.rs | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/pgrx-tests/src/tests/shmem_tests.rs b/pgrx-tests/src/tests/shmem_tests.rs index 460a3f7ee..0dea386ae 100644 --- a/pgrx-tests/src/tests/shmem_tests.rs +++ b/pgrx-tests/src/tests/shmem_tests.rs @@ -8,11 +8,16 @@ //LICENSE //LICENSE Use of this source code is governed by the MIT license that can be found in the LICENSE file. use pgrx::prelude::*; -use pgrx::{pg_shmem_init, PgAtomic, PgHashMap, PgLwLock, PgSharedMemoryInitialization}; +use pgrx::{pg_shmem_init, PgAtomic, PgLwLock, PgSharedMemoryInitialization}; use std::sync::atomic::AtomicBool; +#[cfg(feature = "cshim")] +use pgrx::PgHashMap; + static ATOMIC: PgAtomic = PgAtomic::new(); static LWLOCK: PgLwLock = PgLwLock::new(); + +#[cfg(feature = "cshim")] static HASH_MAP: PgHashMap = PgHashMap::new(500); #[pg_guard] @@ -20,6 +25,8 @@ pub extern "C" fn _PG_init() { // This ensures that this functionality works across PostgreSQL versions pg_shmem_init!(ATOMIC); pg_shmem_init!(LWLOCK); + + #[cfg(feature = "cshim")] pg_shmem_init!(HASH_MAP); } @@ -29,7 +36,10 @@ mod tests { #[allow(unused_imports)] use crate as pgrx_tests; - use crate::tests::shmem_tests::{HASH_MAP, LWLOCK}; + #[cfg(feature = "cshim")] + use crate::tests::shmem_tests::HASH_MAP; + use crate::tests::shmem_tests::LWLOCK; + use pgrx::prelude::*; #[pg_test] @@ -57,6 +67,7 @@ mod tests { let _lock = LWLOCK.exclusive(); } + #[cfg(feature = "cshim")] #[pg_test] pub fn test_pg_hash_map() { use rand::prelude::IteratorRandom; From e077414933560c3fc2fe2e7e87126efb1f41e015 Mon Sep 17 00:00:00 2001 From: Lev Date: Mon, 27 Nov 2023 12:42:34 -0800 Subject: [PATCH 15/15] Address comments --- pgrx-examples/shmem/src/lib.rs | 2 +- pgrx/src/shmem_hash.rs | 63 ++++++++++++++++++++-------------- pgrx/src/spinlock.rs | 8 ++++- 3 files changed, 45 insertions(+), 28 deletions(-) diff --git a/pgrx-examples/shmem/src/lib.rs b/pgrx-examples/shmem/src/lib.rs index 862af5534..0bd396b25 100644 --- a/pgrx-examples/shmem/src/lib.rs +++ b/pgrx-examples/shmem/src/lib.rs @@ -40,7 +40,7 @@ static HASH: PgLwLock> = PgLwLock::new(); static STRUCT: PgLwLock = PgLwLock::new(); static PRIMITIVE: PgLwLock = PgLwLock::new(); static ATOMIC: PgAtomic = PgAtomic::new(); -static HASH_TABLE: PgHashMap = PgHashMap::new(250); +static HASH_TABLE: ShmemHashMap = ShmemHashMap::new(250); #[pg_guard] pub extern "C" fn _PG_init() { diff --git a/pgrx/src/shmem_hash.rs b/pgrx/src/shmem_hash.rs index cbbacdf86..c0f89d3c0 100644 --- a/pgrx/src/shmem_hash.rs +++ b/pgrx/src/shmem_hash.rs @@ -7,20 +7,20 @@ use uuid::Uuid; #[derive(Debug, Eq, PartialEq)] #[non_exhaustive] -pub enum Error { +pub enum ShmemHashMapError { /// Hash table can't have more entries due to fixed allocation size. HashTableFull, } #[derive(Copy, Clone, Debug)] -struct PgHashMapInner { +struct ShmemHashMapInner { htab: *mut pg_sys::HTAB, - elements: u64, + elements: i64, } -unsafe impl PGRXSharedMemory for PgHashMapInner {} -unsafe impl Send for PgHashMapInner {} -unsafe impl Sync for PgHashMapInner {} +unsafe impl PGRXSharedMemory for ShmemHashMapInner {} +unsafe impl Send for ShmemHashMapInner {} +unsafe impl Sync for ShmemHashMapInner {} #[repr(C)] #[derive(Copy, Clone, Debug)] @@ -39,7 +39,7 @@ struct Value { value: V, } -impl Default for PgHashMapInner { +impl Default for ShmemHashMapInner { fn default() -> Self { Self { htab: std::ptr::null_mut(), elements: 0 } } @@ -48,12 +48,12 @@ impl Default for PgHashMapInner { /// A shared memory HashMap using Postgres' `HTAB`. /// This HashMap is used for `pg_stat_statements` and Postgres /// internals to store key/value pairs in shared memory. -pub struct PgHashMap { +pub struct ShmemHashMap { /// HTAB protected by a SpinLock. - htab: OnceCell>, + htab: OnceCell>, /// Max size, allocated at server start. - size: u64, + size: i64, // Markers for key/value types. _phantom_key: std::marker::PhantomData, @@ -82,11 +82,19 @@ macro_rules! value_ptr { }}; } -impl PgHashMap { - /// Create new `PgHashMap`. This still needs to be allocated with +impl ShmemHashMap { + /// Create new `ShmemHashMap`. This still needs to be allocated with /// `pg_shmem_init!` just like any other shared memory structure. - pub const fn new(size: u64) -> PgHashMap { - PgHashMap { + /// + /// # Arguments + /// + /// * `size` - Maximum number of elements in the HashMap. This is allocated + /// at server start and cannot be changed. `i64` is the expected type + /// for `pg_sys::ShmemInitHash`, so we don't attempt runtime conversions + /// unnecessarily. + /// + pub const fn new(size: i64) -> ShmemHashMap { + ShmemHashMap { htab: OnceCell::new(), size, _phantom_key: std::marker::PhantomData, @@ -94,9 +102,10 @@ impl PgHashMap { } } - /// Insert a key and value into the `PgHashMap`. If the key is already - /// present, it will be replaced and returned. If the `PgHashMap` is full, return an error. - pub fn insert(&self, key: K, value: V) -> Result, Error> { + /// Insert a key and value into the `ShmemHashMap`. If the key is already + /// present, it will be replaced and returned. If the `ShmemHashMap` is full, + /// an error is returned. + pub fn insert(&self, key: K, value: V) -> Result, ShmemHashMapError> { let mut found = false; let mut htab = self.htab.get().unwrap().lock(); let (key_ptr, hash_value) = key!(key, htab); @@ -122,7 +131,7 @@ impl PgHashMap { // If we don't do this check, pg will overwrite // some random entry with our key/value pair... if entry.is_null() && htab.elements == self.size { - return Err(Error::HashTableFull); + return Err(ShmemHashMapError::HashTableFull); } let entry = unsafe { @@ -148,12 +157,12 @@ impl PgHashMap { Ok(return_value) } else { // OOM. We pre-allocate at server start, so this should never be an issue. - return Err(Error::HashTableFull); + return Err(ShmemHashMapError::HashTableFull); } } /// Get a value from the HashMap using the key. - /// If the key doesn't exist, return None. + /// If the key doesn't exist, return `None`. pub fn get(&self, key: K) -> Option { let htab = self.htab.get().unwrap().lock(); let (key_ptr, hash_value) = key!(key, htab); @@ -177,7 +186,7 @@ impl PgHashMap { } } - /// Remove the value from the `PgHashMap` and return it. + /// Remove the value from the `ShmemHashMap` and return it. /// If the key doesn't exist, return None. pub fn remove(&self, key: K) -> Option { if let Some(value) = self.get(key) { @@ -203,15 +212,17 @@ impl PgHashMap { } /// Get the number of elements in the HashMap. - pub fn len(&self) -> u64 { + pub fn len(&self) -> i64 { let htab = self.htab.get().unwrap().lock(); htab.elements } } -impl PgSharedMemoryInitialization for PgHashMap { +impl PgSharedMemoryInitialization for ShmemHashMap { fn pg_init(&'static self) { - self.htab.set(PgSpinLock::new(PgHashMapInner::default())).expect("htab cell is not empty"); + self.htab + .set(PgSpinLock::new(ShmemHashMapInner::default())) + .expect("htab cell is not empty"); } fn shmem_init(&'static self) { @@ -227,8 +238,8 @@ impl PgSharedMemoryInitialization for PgHashMa let htab_ptr = unsafe { pg_sys::ShmemInitHash( shm_name.into_raw(), - self.size.try_into().unwrap(), - self.size.try_into().unwrap(), + self.size, + self.size, &mut hash_ctl, (pg_sys::HASH_ELEM | pg_sys::HASH_BLOBS).try_into().unwrap(), ) diff --git a/pgrx/src/spinlock.rs b/pgrx/src/spinlock.rs index 90b56ca95..84c76be35 100644 --- a/pgrx/src/spinlock.rs +++ b/pgrx/src/spinlock.rs @@ -9,6 +9,7 @@ //LICENSE Use of this source code is governed by the MIT license that can be found in the LICENSE file. use crate::pg_sys; use core::mem::MaybeUninit; +use std::fmt; use std::{cell::UnsafeCell, marker::PhantomData}; /// A Rust locking mechanism which uses a PostgreSQL `slock_t` to lock the data. @@ -28,7 +29,6 @@ use std::{cell::UnsafeCell, marker::PhantomData}; /// [`storage/spin.h`]: /// https://github.com/postgres/postgres/blob/1f0c4fa255253d223447c2383ad2b384a6f05854/src/include/storage/spin.h #[doc(alias = "slock_t")] -#[derive(Debug)] pub struct PgSpinLock { item: UnsafeCell, lock: UnsafeCell, @@ -39,6 +39,12 @@ pub struct PgSpinLock { unsafe impl Send for PgSpinLock {} unsafe impl Sync for PgSpinLock {} +impl fmt::Debug for PgSpinLock { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("PgSpinLock").finish() + } +} + impl PgSpinLock { /// Create a new [`PgSpinLock`]. See the type documentation for more info. #[inline]