Database 시장에서 점유율의 순위는 크게 변화하지는 않았지만, 주목할 만한 것은 PostgreSQL의 상승세이다.1 특히 MySQL의 점유율은 갈수록 하락 추세이다. 물론 MariaDB 사용자를 포함하지 않아서일 수도 있다.2 오라클의 장점을 가지면서도 오픈소스로써 무료 데이터베이스인 PostgreSQL의 설치와 설정 과정, 튜닝포인트를 알아보고 MVCC(multiversion concurrency control)의 차이점 또한 간략하게 정리하였다.
테스트를 사용한 환경은 Windows WSL2에 Ubuntu 24.04 LTS 버전을 설치하여 진행했다.3 ?>
는 Shell 프롬프트이다.
?> sudo apt install postgresql postgresql-contrib
?> sudo systemctl status postgresql
?> sudo systemctl enable/disable postgresql
?> sudo systemctl start postgresql
?> sudo -i -u postgres psql
\password postgres #패스워드
?> sudo vi /etc/postgresql/14/main/postgresql.conf
isten_addresses = '*'
?> sudo vi /etc/postgresql/14/main/pg_hba.conf
host all all 0.0.0.0/0 md5 #추가 또는 수정
프로그램 언어들은 예외 핸들링(exception handling) 또는 반환 값(return value) 이라는 두 가지 에러 핸들링 접근 방식 중 한 가지를 사용한다. Rust는 후자를 사용한다.1 이전 글 Rust-004, 러스트 예외/에러 처리에서 복구 가능한 에러를 위한 Result<T, E>
사용법을 살펴봤다.
Rust의 Result는 한가지 에러 타입만 처리가 기본적으로 가능하다. 두 가지 이상의 다른 에러 타입은 처리가 불가능할 때 사용할 수 있는 Custom Error Handling 방법을 이번 글에서 살펴본다. 에러처리 간소화를 위한 thiserror, anyhow 크레이트 예제를 소개하였다.
use std::fs::File;
use std::io::Write;
use std::num::ParseIntError;
fn main() {
println!("{:?}", square("2"));
println!("{:?}", square("invalid"));
}
fn square(val: &str) -> Result<i32, ParseIntError> {
let num = val.parse::<i32>()?;
let mut f = File::open("file.txt")?;
let string_to_write = format!("Square of {} is {}", num, i32::pow(num, 2));
f.write(string_to_write.as_bytes())?;
Ok(i32::pow(num, 2))
}
/*
the trait `From<std::io::Error>` is not implemented for `ParseIntError`
ParseIntError, Error : 에러 타입이 두 가지지만 하나의 에러 타입만 지정
*/
닷넷 7.0 이전 버전에서는 대부분 외부 DLL 파일을 Import 하거나 P/Invoke1를 활용하여 Native DLL(Unmanaged DLL)에 있는 함수를 호출하기 위해 DllImport
를 사용해 왔다. 8.0버전부터는 LibraryImport
의 사용을 권장한다.
LibraryImport가 새로 생겨난 이유는 DllImport가 마샬링을 런타임에서 수행해서 IL 코드를 emit 한다고 하는데 NativeAOT 등 동적으로 IL 코드를 생성할 수 없는 환경에서 쓸 수 없으므로 LibraryImport의 소스 생성기 기능을 이용해 컴파일 시점에서 마샬링 코드를 삽입한다.2
기존에 작성했던 DllImport에서 LibraryImport 스타일로 변경할 때 몇 가지 변경 사항이 있는데 이 부분을 간단한 예제를 통하여 정리하였다. ~.csproj
를 열어 <PropertyGroup>
사이에<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
를 추가한다.
[LibraryImport("user32.DLL", EntryPoint = "ReleaseCapture", StringMarshalling = StringMarshalling.Utf16)]
[UnmanagedCallConv(CallConvs = [typeof(CallConvStdcall)])]
[return: MarshalAs(UnmanagedType.Bool)]
private static partial bool ReleaseCapture();
[LibraryImport("user32.DLL", EntryPoint = "SendMessageW", StringMarshalling = StringMarshalling.Utf16)]
[UnmanagedCallConv(CallConvs = [typeof(CallConvStdcall)])]
[return: MarshalAs(UnmanagedType.SysInt)]
private static partial IntPtr SendMessageW(IntPtr hWnd, uint wMsg, IntPtr wParam, IntPtr lParam);
[LibraryImport("USER32.DLL", EntryPoint = "FindWindowW", StringMarshalling = StringMarshalling.Utf16)]
[UnmanagedCallConv(CallConvs = [typeof(CallConvStdcall)])]
[return: MarshalAs(UnmanagedType.SysInt)]
private static partial IntPtr FindWindowW(string? lpClassName, string? lpWindowName);
public static void DragMoveWindow(string windowTitle)
{
// MainWindow? mainWindow = Application.Current.MainWindow as MainWindow;
// _ = ReleaseCapture();
// _ = SendMessageW(mainWindow == null ? Process.GetCurrentProcess().MainWindowHandle : FindWindowW(null, mainWindow.Title),
// 0x112, 0xf012, 0);
_ = ReleaseCapture();
_ = SendMessageW(FindWindowW(null, windowTitle), 0x112, 0xf012, 0);
}