ちょっと前までは低レベルのプログラムは作れないと思った(情報が無いから)てたけど最近ちゃんと作れるようになってて成長を感じる
なにも考えなくなっちゃう
わかる
作ったの見るだけになる
いつも表示されるから選択できたらと思ってしまう
そうそう
だからそのSQLServerを作るところから始めてみたってわけ
ん?DBエンジン作ろうとしたの?
そりゃ頑張ったなw
意外と簡単にできた
正直ビビってる
オープンソースなのに?
そりゃしてるだろ
逆になんでしてないと思ってんの?
クラッキング経験あるけどDBエンジンにそこまで求めるのはかわいそうよ
アプリケーションサーバー側で防げよといいたい
これ
むしろオープンソースこそ色んな人にめちゃくちゃチェックされてるだろ
このあとソースコード作ってもらってそれで動いた
結論から言うと、**「現在のメモリ構成をそのままメモリコピーしてpageに振り分ける」だけでは、後で正しく読み戻せない可能性が高い**です。
### なぜそのままコピーだけではダメなのか
メモリ上のデータ構造(特にリレーショナルDBでよく使うもの)には、次のような「位置依存」の要素が普通に含まれます。
1. **ポインタ(アドレス)**
– レコード間のリンク、B+Treeの子ノード、ハッシュテーブルのバケットチェーンなど、ほぼすべてがポインタでつながっています。
– メモリコピーした時点のアドレスは、再ロードしたときに別の場所に配置されるため、無効になります。
2. **相対アドレスやオフセットが混在している場合**
– 一部の実装では「ページ内オフセット」を使っていますが、完全にポインタで書かれている場合は修正が必要です。
3. **アロケータ依存の構造**
– スラブアロケータやオブジェクトプールを使っていると、メタデータやフリーリストもアドレスに依存しています。
4. **エンディアンやアラインメント**
– 同じマシンなら問題になりにくいですが、将来的に別環境で動かす場合は影響します。
つまり「そのままmemcpyしてディスクに書いたものを、別のアドレス空間に読み込んだらそのまま動く」という保証はありません。
### 正しくやるための一般的なアプローチ
| 方法 | 内容 | 速度感 | 実装難易度 |
|——|——|——–|————|
| **ポインタのスウィズル(swizzling)** | 保存時にポインタを「ページID + オフセット」に変換し、読み込み時に実際のアドレスに戻す | 比較的高速 | 中~高 |
| **完全に相対アドレスで設計する** | 最初からポインタを使わず、すべて「ベースアドレス + オフセット」で表現する | 最速に近い | 高(設計段階から必要) |
| **シリアライズ(flatten)する** | メモリ構造を一度線形なバイト列に変換して保存し、読み込み時に再構築する | やや遅い | 中 |
| **mmap + 固定アドレスマッピング** | ページを常に同じ仮想アドレスにマップする(稀) | 非常に高速 | 高(OS依存が強い) |
実務的には**「ポインタスウィズル」か「最初から相対アドレス設計」**のどちらかが主流です。
### おすすめの考え方
– **速度を最優先したい場合**
「ページ内はすべて相対オフセットで持つ」設計にすると、memcpyでほぼそのまま書き出せます。読み込み後もアドレス変換が最小限で済みます。
– **実装を簡単にしたい場合**
まず普通にシリアライズ(レコードを1つずつ書いていく)方式で動くものを作り、後から「メモリイメージをそのまま書く」方式に移行するのが安全です。
– **検証方法**
1. メモリ上でデータを作る
2. ページに書き出す
3. 完全にメモリを解放する
4. 別のアドレス空間に読み込む
5. すべてのポインタを辿ってデータが壊れていないかチェックする
この「完全に解放してから読み戻す」テストをしないと、偶然同じアドレスに載って動いてしまうことがあります。
### まとめ
– そのままメモリコピー → **そのままでは正しく取得できない可能性が高い**(ポインタが壊れる)
– 正しくやるには **ポインタを相対化(スウィズル)する** か **最初から相対アドレスで設計する** 必要がある
– 速度を求めるなら「ページ内相対オフセット」設計が最も有利
もし今のメモリ構造(B+Treeなのか、ハッシュなのか、レコードの持ち方など)がもう少し具体的に分かれば、よりピンポイントなアドバイスができます。どんな構造を想定していますか?
using System.Collections.Generic;
using System.IO;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text;
// ============================================================
// 定数・共通型
// ============================================================
public static class DbConst
{
public const int PageSize = 4096;
public const int PageHeaderSize = 64;
}
public enum PageType : byte
{
Meta = 0,
Index = 1, // B+Treeノード
Data = 2, // レコード・テーブルヘッダなど
Catalog = 3, // テーブルカタログ用
Free = 255
}
public enum ColumnType : byte
{
Int32 = 1,
String = 2
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct PagePtr
{
public int PageId;
public ushort Offset;
public static PagePtr Null => new() { PageId = -1, Offset = 0 };
public bool IsNull => PageId < 0;
public override string ToString() => IsNull ? “Null” : $”({PageId}:{Offset})”;
}
半沢直樹2期の0話で吉沢亮がクライアントに提案してたシステム高速化手法にもそれ入ってた
昔はエムアロックやらフリー関数でシコシコやってたなw
ていうかなんかイッチくんがせっせとコード貼ってるの尊いわw
// ページ
// ============================================================
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct PageHeader
{
public int PageId;
public PageType Type;
public ushort Used;
public ushort ItemCount;
public int NextPageId; // 汎用(Catalogの場合は次のカタログページ)
public int Checksum;
}
public sealed class Page
{
public byte[] Data { get; } = new byte[DbConst.PageSize];
public ref PageHeader Header =>
ref Unsafe.As<byte, PageHeader>(ref Data[0]);
public Page(int pageId, PageType type)
{
Header.PageId = pageId;
Header.Type = type;
Header.Used = (ushort)DbConst.PageHeaderSize;
Header.ItemCount = 0;
Header.NextPageId = -1;
Header.Checksum = 0;
}
public Page(byte[] raw)
{
if (raw.Length != DbConst.PageSize)
throw new ArgumentException(“Invalid page size”);
Buffer.BlockCopy(raw, 0, Data, 0, DbConst.PageSize);
}
public int Allocate(int size, int alignment = 8)
{
int aligned = (Header.Used + alignment – 1) & \~(alignment – 1);
if (aligned + size > DbConst.PageSize)
return -1;
int offset = aligned;
Header.Used = (ushort)(aligned + size);
Header.ItemCount++;
return offset;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ref T Get<T>(int offset) where T : unmanaged
=> ref Unsafe.As<byte, T>(ref Data[offset]);
public Span<byte> GetBytes(int offset, int length)
=> Data.AsSpan(offset, length);
public byte[] ToArray() => (byte[])Data.Clone();
}
インメモリDBは知ってる
高速なのも知ってる
ただその仕様上電源を落とすとデータが飛ぶから永続で使用できるようにストレージ方式にした
あとメモリが多くないと大きなデータは保存できないからね
今めっちゃ使ってる
オブジェクトDBって結合(Join)出来ないけどその辺不満ない感じ?
オブジェクトから全部辿って行く感じなのか?
ORマッパーのこと?それRDBとベッタリしてるやつじゃん☺ベタベタだよ
ORマッパーはSQLのデータをプログラムのデータ構造に入れるやつだよね?
オブジェクト型DBってのが最近あってこいつがORマッパーが無いけどORマッパーやったみたいにプログラムで扱える便利なやつって認識で最近使われ出してる
聞くところによるとJoinみたいなテーブル同士で結合するのがあんま得意でないというか出来ないからその辺どうやってんだろうな?って思って
nosqlとかハドゥープとかまだ生きてるの?
最近めっきり聞かなくなった…
それとは違ったやつが最前線では台頭して来てたりするのかしら?
そんなやつだろうな
知らんけどw
複雑な結合いらんRDBもあるんよインフラなんてw
いや俺はただのSIerだよ
派遣で既存のシステムを使わざるを得ない人
派遣先が電力系ってだけ
この機械使う人が予約してるからこの機械は今使えませーんみたいなアプリを開発したり保守したり
まぁ基本保守がメイン



コメント